Making The Most Of Temp Tables Part 1: Parallel Inserts

Sing Along

If you have a workload that uses #temp tables to stage intermediate results, and you probably do because you’re smart, it might be worth taking advantage of being able to insert into the #temp table in parallel.

Remember that you can’t insert into @table variables in parallel, unless you’re extra sneaky. Don’t start.

If your code is already using the SELECT ... INTO #some_table pattern, you’re probably already getting parallel inserts. But if you’re following the INSERT ... SELECT ... pattern, you’re probably not, and, well, that could be holding you back.

Pile On

Of course, there are some limitations. If your temp table has indexes, primary keys, or an identity column, you won’t get the parallel insert no matter how hard you try.

The demo code is available here if you’d like to test it out.

amanda lear

The first thing to note is that inserting into an indexed temp table, parallel or not, does slow things down. If your goal is the fastest possible insert, you may want to create the index later.

No Talent

When it comes to parallel inserts, you do need the TABLOCK, or TABLOCKX hint to get it, e.g. INSERT #tp WITH(TABLOCK) which is sort of annoying.

But you know. It’s the little things we do that often end up making the biggest differences. Another little thing we may need to tinker with is DOP.

little pigs

Here are the query plans for 3 fully parallel inserts into an empty, index-less temp #table. Note the execution times dropping as DOP increases. At DOP 4, the insert really isn’t any faster than the serial insert.

If you start experimenting with this trick, and don’t see noticeable improvements at your current DOP, you may need to  bump it up to see throughput increases.

Also remember that if you’re doing this with clustered column store indexes, it can definitely make things worse.

Page Supplier

Though the speed ups above at higher DOPs are largely efficiency boosters while reading from the Posts table, the speed does stay consistent through the insert.

If we crank one of the queries that gets a serial insert up to DOP 12, we lose some speed when we hit the table.


Next time you’re tuning a query and want to drop some data into a temp table, you should experiment with this technique.

Thanks for reading!

A Word From Our Sponsors

First, a huge thank you to everyone who has bought my training so far. You all are incredible, and I owe all of you a drink.

Your support means a lot to me, and allows me to do nice stuff for other people, like give training away for free.

So far, I’ve donated $45k (!!!) worth of training to folks in need, no questions asked.

Next year, I’d like to keep doing the same thing. I’d also like to produce a whole lot more training to add value to the money you spend. In order to do that, I need to take time off from consulting, which isn’t easy to do. I’m not crying poor, but saying no to work for chunks of time isn’t easy for a one-person party.

I’m hoping that I can make enough in training bucks to make that possible.

Because this sale is extra sale-y, I’ve decided to name it after the blackest black known to man.

From today until December 31st, you can get all 25 hours of my recorded training content for just $100.00. If you click the link below to add everything to your cart, and use the discount code AllFor100 to apply a discount to your cart.




Some fine print: It only works if you add EVERYTHING. It’s a fixed amount discount code that you need to spend a certain amount to have kick in.

Thank for reading, and for your support.

10 thoughts on “Making The Most Of Temp Tables Part 1: Parallel Inserts

  1. Sounds like something Microsoft could partly optimize partly themselves, right?
    If query pattern: “insert into #some_table select from .. ” (and cost > cost threshold for parallellism) then apply the tablock

    Or, why is a tablock even required for a #some_table?

      1. Right sorry 😉 what I meant to say was that for regular tables the tablock hint is a concurrency aspect.
        Since a #temp table the table is private to the session, the concurrency aspect isn’t there.
        So why would I not want the tablock for a #temp table as a default behaviour if that helps with the parallel inserts?

  2. I tried this recently for a stored procedure. Unexpectedly, simply adding the TABLOCK resulted in deadlocks. This was found by the testing team, so I never saw the deadlock graph, but I assume the parallel threads were deadlocking with themselves. Nothing else would have needed a lock on the temp table and it is Azure SQL database so the SELECTs in the several INSERT…SELECT into the same temp table wouldn’t have caused a lock on the source table either.

    “Store proc gives result all the time if we execute it alone, however it gives “deadlocked on lock” error if we execute it in a script This script we are using to compare the stored proc results to ensure there is no mismatch in results before and after the optimization.” The test script inserts the return data from the stored procedure into a temp table using INSERT…SELECT.

    Any ideas on how to avoid this?

Leave a Reply

Your email address will not be published. Required fields are marked *