Sql-server – Different execution plans during INSERT at @table variable and #temporary table

performanceperformance-tuningsql server

I faced with strange situation: inserting of ~800 000 rows into table variable is much more faster than inserting (with the same select) into temporary table. INSERT is under stored procedure. SELECT have parameters from stored procedure.

Sample code below:

create procedure p1
    @Param1 int
AS
    declare @t table (id int)

    insert into @t
        select id  
        from dbo.SomeTable 
        where SomeField = @Param1

And if I change @t to #t – than I have more than 2.5 difference in procedure's execution time.

All the time as DBA I thought that so big row count should be processed in temporary tables… But now, I don't think so 🙂

Anyway, I'm just trying to understand what is going on and why the same SELECT have different execution plans during INSERT.

The same case (as I thought) was here: INSERT performance difference between temporary tables and table variable. But I have the opposite situation – INSERT into # is SLOWER than @

So, do you have any ideas?

  1. what is the better in this case: use @ or #?
  2. why do I get different execution plans ?

Execution plan here: https://drive.google.com/file/d/0B1iqgEJ5a7vfcjAwMmtJaVFrNWM/view?usp=sharing

Thank you in advance!

P.S. Microsoft SQL Server 2012 (SP1) – 11.0.3128.0 (X64)

P.P.S. I've found really good article about temporary tables and table variables here: What's the difference between a temp table and table variable in SQL Server?. But, unfortunately, it didn't help me.

Best Answer

The first thing that I noticed is that the query plan compilation time was over 3 seconds for each query. Wow, this is a really complex query!

Because the solution space of potential execution plans is so large (it grows exponentially with the number of the number of objects involved in the query), SQL Server is only going to be able to explore a tiny fraction of the potential query plans when coming up with a plan for these queries. Remember that SQL Server's job isn't to create the best query plan possible, but instead to create a query plan that is good enough and to do so as quickly as possible.

I have often found that small changes in the way a query is formulated, even if they don't impact the logic of the query, can have a significant impact on the query plan. Anecdotally, this grows more and more likely as the query grows more and more complex. One possible reason that this could happen is that a tweak to the query might cause SQL Server to begin cost-based optimization with a different initial plan. As cost-based optimization proceeds, this different starting point could yield a different exploration of the space of potential query plans--kind of like a different random seed impacts random number generation. Note that the query plans you provided are significantly different (compare images of the plan shape below!) and SQL Server actually does estimate that the @table variable plan is slightly cheaper.

In terms of why the table variable vs. temp table would have such an impact on cost-based optimization, I'll hazard an only-partially-educated guess: inserting into a table variable forces a serial plan (see the NonParallelPlanReason of CouldNotGenerateValidParallelPlan that appears in the table variable plan, but not the temp table plan), and this may impact the code path that the query optimizer takes either generating an initial plan or in some phase of plan optimization.

If possible, the next step that I would try is to simplify the query so that fewer tables are used and/or the query is split into multiple queries (with intermediate #temp tables) so that each query is simpler and has better statistics available. If that's not possible, you could also try more hacky options such as using query hints (e.g., force MAXDOP 1 on the temp table query, and see if the plan comes out more like the table variable query).

Query plan with #temp table: enter image description here

Query plan with @table variable: enter image description here

And finally, if you are interested in going a little bit deeper into how the query optimizer works, I have found Paul White's blog to be a great resource!