Question

I currently have a performance issue with a query (that is more complicated than the example below). Originally the query would run and take say 30 seconds, then when I switched out the use of a table variable to using a temp table instead, the speed is cut down to a few seconds.

Here is a trimmed down version using a table variable:

-- Store XML into tables for use in query
DECLARE @tCodes TABLE([Code] VARCHAR(100))

INSERT INTO
    @tCodes
SELECT 
    ParamValues.ID.value('.','VARCHAR(100)') AS 'Code'
FROM 
    @xmlCodes.nodes('/ArrayOfString/string') AS ParamValues(ID)


SELECT
    'SummedValue' = SUM(ot.[Value])
FROM
    [SomeTable] st (NOLOCK)
JOIN
    [OtherTable] ot (NOLOCK)
    ON  ot.[SomeTableID] = st.[ID]
WHERE
    ot.[CodeID] IN (SELECT [Code] FROM @tCodes) AND 
    st.[Status] = 'ACTIVE' AND
    YEAR(ot.[SomeDate]) = 2013 AND  
    LEFT(st.[Identifier], 11) = @sIdentifier

Here is the version with the temp table which performs MUCH faster:

SELECT 
    ParamValues.ID.value('.','VARCHAR(100)') AS 'Code'
INTO
    #tCodes
FROM 
    @xmlCodes.nodes('/ArrayOfString/string') AS ParamValues(ID)


SELECT
    'SummedValue' = SUM(ot.[Value])
FROM
    [SomeTable] st (NOLOCK)
JOIN
    [OtherTable] ot (NOLOCK)
    ON  ot.[SomeTableID] = st.[ID]
WHERE
    ot.[CodeID] IN (SELECT [Code] FROM #tCodes) AND 
    st.[Status] = 'ACTIVE' AND
    YEAR(ot.[SomeDate]) = 2013 AND  
    LEFT(st.[Identifier], 11) = @sIdentifier

The problem I have with performance is solved with the change but I just don't understand why it fixes the issue and would prefer to know why. It could be related to something else in the query but all I have changed in the stored proc (which is much more complicated) is to switch from using a table variable to using a temp table. Any thoughts?

Was it helpful?

Solution

The differences and similarities between table variables and #temp tables are looked at in depth in my answer here.

Regarding the two queries you have shown (unindexed table variable vs unindexed temp table) three possibilities spring to mind.

  1. INSERT ... SELECT to table variables is always serial. The SELECT can be parallelised for temp tables.
  2. Temp tables can have column statistics histograms auto created for them.
  3. Usually the cardinality of table variables is assumed to be 0 (when they are compiled when the table is empty)

From the code you have shown (3) seems the most likely explanation.

This can be resolved by using OPTION (RECOMPILE) to recompile the statement after the table variable has been populated.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top