Stavo guardando l'articolo qui Tabelle temporanee contro variabili di tabella e il loro effetto sulle prestazioni di SQL Server e su SQL Server 2008 è stato in grado di riprodurre risultati simili a quelli mostrati lì per il 2005.
Quando si eseguono le stored procedure (definizioni di seguito) con solo 10 righe, la versione della variabile della tabella in uscita esegue la versione della tabella temporanea per più di due volte.
Ho cancellato la cache delle procedure ed eseguito entrambe le procedure memorizzate 10.000 volte, quindi ho ripetuto il processo per altre 4 esecuzioni. Risultati di seguito (tempo in ms per batch)
T2_Time V2_Time
----------- -----------
8578 2718
6641 2781
6469 2813
6766 2797
6156 2719
La mia domanda è: qual è la ragione per la migliore prestazione della versione variabile della tabella?
Ho fatto qualche indagine. ad es. guardando i contatori delle prestazioni con
SELECT cntr_value
from sys.dm_os_performance_counters
where counter_name = 'Temp Tables Creation Rate';
conferma che in entrambi i casi gli oggetti temporanei vengono memorizzati nella cache dopo la prima esecuzione come previsto anziché essere nuovamente creati da zero per ogni chiamata.
Analogamente il rintracciamento Auto Stats
, SP:Recompile
, SQL:StmtRecompile
eventi in Profiler (schermata qui sotto) mostra che tali eventi si verificano solo una volta (la prima chiamata della #temp
procedura memorizzata tabella) e gli altri 9.999 esecuzioni non sollevare uno di questi eventi. (La versione della variabile della tabella non ottiene nessuno di questi eventi)
L'overhead leggermente maggiore della prima esecuzione della procedura memorizzata non può in alcun modo tenere conto della grande differenza complessiva, tuttavia, poiché bastano ancora pochi ms per svuotare la cache delle procedure ed eseguire entrambe le procedure una volta, quindi non credo che le statistiche o la ricompilazione può essere la causa.
Creare oggetti di database richiesti
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
Test script
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
tabella solo una volta nonostante vengano cancellate e ripopolate altre 9.999 volte successive.