Estaba mirando el artículo aquí Las tablas temporales frente a las variables de tabla y su efecto en el rendimiento de SQL Server y en SQL Server 2008 pudieron reproducir resultados similares a los mostrados allí para 2005.
Al ejecutar los procedimientos almacenados (definiciones a continuación) con solo 10 filas, la versión variable de la tabla supera la versión de la tabla temporal más de dos veces.
Limpié el caché de procedimientos y ejecuté ambos procedimientos almacenados 10,000 veces y luego repetí el proceso para otras 4 ejecuciones. Resultados a continuación (tiempo en ms por lote)
T2_Time V2_Time
----------- -----------
8578 2718
6641 2781
6469 2813
6766 2797
6156 2719
Mi pregunta es: ¿Cuál es la razón del mejor rendimiento de la versión de tabla variable?
He investigado un poco. Por ejemplo, mirar los contadores de rendimiento con
SELECT cntr_value
from sys.dm_os_performance_counters
where counter_name = 'Temp Tables Creation Rate';
confirma que en ambos casos los objetos temporales se almacenan en caché después de la primera ejecución como se esperaba en lugar de crearse desde cero nuevamente para cada invocación.
Del mismo modo trazando el Auto Stats
, SP:Recompile
, SQL:StmtRecompile
eventos en Profiler (imagen abajo) muestra que estos eventos ocurren solamente una vez (en la primera invocación del #temp
procedimiento almacenado mesa) y los otros 9.999 ejecuciones no plantear cualquiera de estos eventos. (La versión de la variable de tabla no obtiene ninguno de estos eventos)
Sin embargo, la sobrecarga levemente mayor de la primera ejecución del procedimiento almacenado de ninguna manera puede explicar la gran diferencia general, ya que solo lleva unos pocos ms borrar el caché del procedimiento y ejecutar ambos procedimientos una vez, por lo que no creo que las estadísticas o Las recompilaciones pueden ser la causa.
Crear objetos de base de datos necesarios
CREATE DATABASE TESTDB_18Feb2012;
GO
USE TESTDB_18Feb2012;
CREATE TABLE NUM
(
n INT PRIMARY KEY,
s VARCHAR(128)
);
WITH NUMS(N)
AS (SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY $/0)
FROM master..spt_values v1,
master..spt_values v2)
INSERT INTO NUM
SELECT N,
'Value: ' + CONVERT(VARCHAR, N)
FROM NUMS
GO
CREATE PROCEDURE [dbo].[T2] @total INT
AS
CREATE TABLE #T
(
n INT PRIMARY KEY,
s VARCHAR(128)
)
INSERT INTO #T
SELECT n,
s
FROM NUM
WHERE n%100 > 0
AND n <= @total
DECLARE @res VARCHAR(128)
SELECT @res = MAX(s)
FROM NUM
WHERE n <= @total
AND NOT EXISTS(SELECT *
FROM #T
WHERE #T.n = NUM.n)
GO
CREATE PROCEDURE [dbo].[V2] @total INT
AS
DECLARE @V TABLE (
n INT PRIMARY KEY,
s VARCHAR(128))
INSERT INTO @V
SELECT n,
s
FROM NUM
WHERE n%100 > 0
AND n <= @total
DECLARE @res VARCHAR(128)
SELECT @res = MAX(s)
FROM NUM
WHERE n <= @total
AND NOT EXISTS(SELECT *
FROM @V V
WHERE V.n = NUM.n)
GO
Script de prueba
SET NOCOUNT ON;
DECLARE @T1 DATETIME2,
@T2 DATETIME2,
@T3 DATETIME2,
@Counter INT = 0
SET @T1 = SYSDATETIME()
WHILE ( @Counter < 10000)
BEGIN
EXEC dbo.T2 10
SET @Counter += 1
END
SET @T2 = SYSDATETIME()
SET @Counter = 0
WHILE ( @Counter < 10000)
BEGIN
EXEC dbo.V2 10
SET @Counter += 1
END
SET @T3 = SYSDATETIME()
SELECT DATEDIFF(MILLISECOND,@T1,@T2) AS T2_Time,
DATEDIFF(MILLISECOND,@T2,@T3) AS V2_Time
#temp
tabla una vez a pesar de que se borran y se vuelven a llenar otras 9.999 veces después de eso.