Nella tua domanda, descrivi dettagliatamente alcuni test che hai preparato dove "dimostri" che l'opzione di aggiunta è più rapida rispetto al confronto delle colonne discrete. Sospetto che la tua metodologia di prova possa essere viziata in diversi modi, come hanno accennato @gbn e @srutzky.
Innanzitutto, è necessario assicurarsi di non testare SQL Server Management Studio (o qualsiasi client si stia utilizzando). Ad esempio, se stai eseguendo un SELECT *
da una tabella con 3 milioni di righe, stai principalmente testando la capacità di SSMS di estrarre righe da SQL Server e renderle sullo schermo. Stai molto meglio usare qualcosa di simile SELECT COUNT(1)
che annulla la necessità di tirare milioni di righe attraverso la rete e renderle sullo schermo.
In secondo luogo, è necessario conoscere la cache dei dati di SQL Server. In genere, testiamo la velocità di lettura dei dati dall'archiviazione e dell'elaborazione di tali dati da una cache fredda (ovvero i buffer di SQL Server sono vuoti). Occasionalmente, ha senso eseguire tutti i test con una cache calda, ma è necessario affrontare esplicitamente i test con questo in mente.
Per un test della cache fredda, è necessario eseguire CHECKPOINT
e DBCC DROPCLEANBUFFERS
prima di ogni esecuzione del test.
Per il test che hai posto nella tua domanda, ho creato il seguente banco di prova:
IF COALESCE(OBJECT_ID('tempdb..#SomeTest'), 0) <> 0
BEGIN
DROP TABLE #SomeTest;
END
CREATE TABLE #SomeTest
(
TestID INT NOT NULL
PRIMARY KEY
IDENTITY(1,1)
, A INT NOT NULL
, B FLOAT NOT NULL
, C MONEY NOT NULL
, D BIGINT NOT NULL
);
INSERT INTO #SomeTest (A, B, C, D)
SELECT o1.object_id, o2.object_id, o3.object_id, o4.object_id
FROM sys.objects o1
, sys.objects o2
, sys.objects o3
, sys.objects o4;
SELECT COUNT(1)
FROM #SomeTest;
Ciò restituisce un conteggio di 260.144.641 sulla mia macchina.
Per testare il metodo "addizione", eseguo:
CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE (st.A + st.B + st.C + st.D) = 0;
GO
SET STATISTICS IO, TIME OFF;
La scheda messaggi mostra:
Tabella '#SomeTest'. Conteggio scansioni 3, letture logiche 1322661, letture fisiche 0, letture avanti 1313877, letture logiche lob 0, letture fisiche lob 0, letture read lob 0.
Tempi di esecuzione di SQL Server: tempo CPU = 49047 ms, tempo trascorso = 173451 ms.
Per il test "colonne discrete":
CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE st.A = 0
AND st.B = 0
AND st.C = 0
AND st.D = 0;
GO
SET STATISTICS IO, TIME OFF;
di nuovo, dalla scheda messaggi:
Tabella '#SomeTest'. Conteggio scansioni 3, letture logiche 1322661, letture fisiche 0, letture read-ahead 1322661, letture logiche lob 0, letture fisiche lob 0, letture read lob 0.
Tempi di esecuzione di SQL Server: tempo CPU = 8938 ms, tempo trascorso = 162581 ms.
Dalle statistiche sopra puoi vedere la seconda variante, con le colonne discrete rispetto a 0, il tempo trascorso è di circa 10 secondi più breve e il tempo della CPU è circa 6 volte inferiore. Le lunghe durate nei miei test sopra sono principalmente il risultato della lettura di molte righe dal disco. Se si abbassa il numero di righe a 3 milioni, i rapporti restano più o meno gli stessi ma i tempi trascorsi diminuiscono notevolmente, poiché l'I / O del disco ha un effetto molto minore.
Con il metodo "Aggiunta":
Tabella '#SomeTest'. Conteggio scansioni 3, letture logiche 15255, letture fisiche 0, letture read-ahead 0, letture log lob 0, letture fisiche lob 0, letture read lob 0.
Tempi di esecuzione di SQL Server: tempo CPU = 499 ms, tempo trascorso = 256 ms.
Con il metodo "colonne discrete":
Tabella '#SomeTest'. Conteggio scansioni 3, letture logiche 15255, letture fisiche 0, letture read-ahead 0, letture log lob 0, letture fisiche lob 0, letture read lob 0.
Tempi di esecuzione di SQL Server: tempo CPU = 94 ms, tempo trascorso = 53 ms.
Cosa farà davvero la differenza per questo test? Un indice appropriato, come ad esempio:
CREATE INDEX IX_SomeTest ON #SomeTest(A, B, C, D);
Il metodo "addizione":
Tabella '#SomeTest'. Conteggio scansioni 3, letture logiche 14235, letture fisiche 0, letture read-ahead 0, letture log lob 0, letture fisiche lob 0, letture read lob 0.
Tempi di esecuzione di SQL Server: tempo CPU = 546 ms, tempo trascorso = 314 ms.
Il metodo "colonne discrete":
Tabella '#SomeTest'. Conteggio scansioni 1, letture logiche 3, letture fisiche 0, letture avanti 0, letture logiche lob 0, letture fisiche lob 0, letture read lob 0.
Tempi di esecuzione di SQL Server: tempo CPU = 0 ms, tempo trascorso = 0 ms.
Il piano di esecuzione per ogni query (con l'indice sopra in atto) è abbastanza eloquente.
Il metodo "addizione", che deve eseguire una scansione dell'intero indice:
e il metodo "colonne discrete", che può cercare la prima riga dell'indice in cui la colonna dell'indice principale A
è zero: