Dans votre question, vous détaillez certains tests que vous avez préparés où vous "prouvez" que l'option d'ajout est plus rapide que la comparaison des colonnes discrètes. Je soupçonne que votre méthodologie de test peut être défectueuse de plusieurs manières, comme l'ont fait référence à @gbn et @srutzky.
Tout d'abord, vous devez vous assurer que vous ne testez pas SQL Server Management Studio (ou le client que vous utilisez). Par exemple, si vous exécutez une SELECT *
table à partir de 3 millions de lignes, vous testez principalement la capacité de SSMS à extraire des lignes de SQL Server et à les afficher à l'écran. Il vaut mieux utiliser quelque chose comme SELECT COUNT(1)
qui annule la nécessité de tirer des millions de lignes sur le réseau et de les afficher à l'écran.
Deuxièmement, vous devez connaître le cache de données de SQL Server. En règle générale, nous testons la vitesse de lecture des données du stockage et du traitement de ces données à partir d'un cache froid (c'est-à-dire que les tampons de SQL Server sont vides). Parfois, il est logique de faire tous vos tests avec un cache chaud, mais vous devez aborder vos tests de manière explicite dans cet esprit.
Pour un test de cache froid, vous devez exécuter CHECKPOINT
et DBCC DROPCLEANBUFFERS
avant chaque exécution du test.
Pour le test que vous avez demandé dans votre question, j'ai créé le banc d'essai suivant:
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;
Cela renvoie un nombre de 260 144 641 sur ma machine.
Pour tester la méthode "addition", je lance:
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;
L'onglet messages affiche:
Tableau '#SomeTest'. Nombre de balayages 3, lectures logiques 1322661, lectures physiques 0, lectures en lecture anticipée 1313877, lob lectures logiques 0, lob lectures physiques 0, lob lectures anticipées en lecture 0.
Temps d'exécution SQL Server: temps CPU = 49047 ms, temps écoulé = 173451 ms.
Pour le test "colonnes discrètes":
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;
encore une fois, dans l'onglet messages:
Tableau '#SomeTest'. Nombre de balayages 3, lectures logiques 1322661, lectures physiques 0, lectures anticipées 1322661, lob lectures logiques 0, lob lectures physiques 0, lob lectures anticipées lisent 0.
Temps d'exécution SQL Server: temps CPU = 8938 ms, temps écoulé = 162581 ms.
D'après les statistiques ci-dessus, vous pouvez voir la deuxième variante, avec les colonnes discrètes par rapport à 0, le temps écoulé est environ 10 secondes plus court et le temps CPU est environ 6 fois moins. Les longues durées de mes tests ci-dessus sont principalement le résultat de la lecture d'un grand nombre de lignes à partir du disque. Si vous réduisez le nombre de lignes à 3 millions, vous voyez que les ratios restent à peu près les mêmes, mais les temps écoulés chutent sensiblement, car les E / S disque ont beaucoup moins d'effet.
Avec la méthode "Addition":
Tableau '#SomeTest'. Nombre de balayages 3, lectures logiques 15255, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0.
Temps d'exécution SQL Server: temps CPU = 499 ms, temps écoulé = 256 ms.
Avec la méthode des "colonnes discrètes":
Tableau '#SomeTest'. Nombre de balayages 3, lectures logiques 15255, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0.
Temps d'exécution SQL Server: temps CPU = 94 ms, temps écoulé = 53 ms.
Qu'est-ce qui fera vraiment une grande différence pour ce test? Un index approprié, tel que:
CREATE INDEX IX_SomeTest ON #SomeTest(A, B, C, D);
La méthode "d'addition":
Tableau '#SomeTest'. Nombre de balayages 3, lectures logiques 14235, lectures physiques 0, lectures anticipées 0, lob lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0.
Temps d'exécution SQL Server: temps CPU = 546 ms, temps écoulé = 314 ms.
La méthode des "colonnes discrètes":
Tableau '#SomeTest'. Nombre de balayages 1, lectures logiques 3, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0.
Temps d'exécution SQL Server: temps CPU = 0 ms, temps écoulé = 0 ms.
Le plan d'exécution pour chaque requête (avec l'index ci-dessus en place) est assez révélateur.
La méthode "addition", qui doit effectuer un scan de l'index entier:
et la méthode des "colonnes discrètes", qui peut rechercher la première ligne de l'index où la colonne d'index de tête A
, est nulle: