In Ihrer Frage beschreiben Sie einige von Ihnen vorbereitete Tests, in denen Sie "beweisen", dass die Hinzufügungsoption schneller ist als der Vergleich der einzelnen Spalten. Ich vermute, dass Ihre Testmethode in mehrfacher Hinsicht fehlerhaft ist, wie @gbn und @srutzky angedeutet haben.
Zunächst müssen Sie sicherstellen, dass Sie SQL Server Management Studio (oder den von Ihnen verwendeten Client) nicht testen. Wenn Sie beispielsweise SELECT *
eine Tabelle mit 3 Millionen Zeilen ausführen, testen Sie hauptsächlich die Fähigkeit von SSMS, Zeilen von SQL Server abzurufen und auf dem Bildschirm darzustellen. Sie sind weitaus besser dran, wenn Sie etwas verwenden, SELECT COUNT(1)
das die Notwendigkeit aufhebt, Millionen von Zeilen über das Netzwerk zu ziehen und sie auf dem Bildschirm wiederzugeben.
Zweitens müssen Sie den Datencache von SQL Server kennen. In der Regel testen wir die Geschwindigkeit, mit der Daten aus dem Speicher gelesen und aus einem Cold-Cache verarbeitet werden (dh die Puffer von SQL Server sind leer). Gelegentlich ist es sinnvoll, alle Tests mit einem Warm-Cache durchzuführen, aber Sie müssen diesbezüglich explizit vorgehen.
Für einen Cold-Cache-Test müssen Sie CHECKPOINT
und DBCC DROPCLEANBUFFERS
vor jedem Testlauf ausführen.
Für den Test, nach dem Sie in Ihrer Frage gefragt haben, habe ich den folgenden Prüfstand erstellt:
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;
Dies ergibt eine Anzahl von 260.144.641 auf meinem Computer.
Um die Methode "addition" zu testen, führe ich Folgendes aus:
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;
Die Registerkarte Nachrichten zeigt:
Tabelle '#SomeTest'. Scananzahl 3, logische Lesevorgänge 1322661, physische Lesevorgänge 0, Vorauslesevorgänge 1313877, logische LOB-Lesevorgänge 0, physische LOB-Lesevorgänge 0, Vorauslesevorgänge 0.
SQL Server-Ausführungszeiten: CPU-Zeit = 49047 ms, verstrichene Zeit = 173451 ms.
Für den Test "Diskrete Spalten":
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;
Wieder auf der Registerkarte Nachrichten:
Tabelle '#SomeTest'. Scananzahl 3, logische Lesevorgänge 1322661, physische Lesevorgänge 0, Vorauslesevorgänge 1322661, logische Lobs-Lesevorgänge 0, physikalische Lobs-Lesevorgänge 0, Lobs-Vorauslesevorgänge 0.
SQL Server-Ausführungszeiten: CPU-Zeit = 8938 ms, verstrichene Zeit = 162581 ms.
In den Statistiken oben sehen Sie die zweite Variante mit den diskreten Spalten im Vergleich zu 0, die verstrichene Zeit ist ungefähr 10 Sekunden kürzer und die CPU-Zeit ist ungefähr 6-mal kürzer. Die langen Zeiträume in meinen obigen Tests sind hauptsächlich auf das Lesen vieler Zeilen von der Festplatte zurückzuführen. Wenn Sie die Anzahl der Zeilen auf 3 Millionen verringern, bleiben die Verhältnisse in etwa gleich, die verstrichenen Zeiten sinken jedoch merklich, da die Datenträger-E / A-Vorgänge wesentlich weniger wirksam sind.
Mit der Methode "Addition":
Tabelle '#SomeTest'. Scan-Anzahl 3, logische Lesevorgänge 15255, physikalische Lesevorgänge 0, Vorauslesevorgänge 0, logische Lobs-Lesevorgänge 0, physikalische Lobs-Vorauslesevorgänge 0.
SQL Server-Ausführungszeiten: CPU-Zeit = 499 ms, verstrichene Zeit = 256 ms.
Mit der Methode "Diskrete Spalten":
Tabelle '#SomeTest'. Scan-Anzahl 3, logische Lesevorgänge 15255, physikalische Lesevorgänge 0, Vorauslesevorgänge 0, logische Lobs-Lesevorgänge 0, physikalische Lobs-Vorauslesevorgänge 0.
SQL Server-Ausführungszeiten: CPU-Zeit = 94 ms, verstrichene Zeit = 53 ms.
Was macht für diesen Test einen wirklich großen Unterschied aus? Ein entsprechender Index wie:
CREATE INDEX IX_SomeTest ON #SomeTest(A, B, C, D);
Die "Additions" -Methode:
Tabelle '#SomeTest'. Scananzahl 3, logische Lesevorgänge 14235, physische Lesevorgänge 0, Vorauslesevorgänge 0, logische Lobs-Lesevorgänge 0, physikalische Lobs-Lesevorgänge 0, Lobs-Vorauslesevorgänge 0.
SQL Server-Ausführungszeiten: CPU-Zeit = 546 ms, verstrichene Zeit = 314 ms.
Die "diskrete Spalten" -Methode:
Tabelle '#SomeTest'. Scananzahl 1, logische Lesevorgänge 3, physische Lesevorgänge 0, Vorauslesevorgänge 0, logische Lobs-Lesevorgänge 0, physikalische Lobs-Lesevorgänge 0, Lobs-Vorauslesevorgänge 0.
SQL Server-Ausführungszeiten: CPU-Zeit = 0 ms, verstrichene Zeit = 0 ms.
Der Ausführungsplan für jede Abfrage (mit dem obigen Index) ist ziemlich aussagekräftig.
Die Methode "addition", mit der der gesamte Index durchsucht werden muss:
und die "diskrete Spalten" -Methode, die nach der ersten Zeile des Index suchen kann, in der die führende Indexspalte A
Null ist: