Leistung von a = 0 und b = 0 und… z = 0 gegen a + b + c + d = 0

20

Dies ist eine einfache Frage, auf die ich anscheinend keine Antwort finden kann.

In Bezug auf die Leistung: Wenn ich eine WHEREKlausel wie " a=0 and b=0 and ... z=0Würde ich eine Leistung erbringen, wenn ich diese Bedingung durch" ersetze a+b+...+z=0?

Mit anderen Worten: Gibt es einen Leistungsgewinn, wenn Sie Folgendes ersetzen?

Select * 
From MyTable 
Where A=0 and B=0 and C=0 and D=0...

Mit

Select * 
From MyTable 
Where A+B+C+D=0...

Ich weiß, dass es von Indizes abhängen kann, aber zu diesem Zweck sagen wir einfach, dass es keine Indizes gibt. Ist der arithmetische Operator (+) besser als ein logischer Operator "ODER" oder "UND"?

Ich habe den Eindruck, dass die Addition mit UNDs oder ODERs besser abschneidet als mehrere Bedingungen.

Testergebnisse

Auf einer Tabelle von 4,2 Millionen Zeilen

Rückgabe von Zeilen mit A = 0 B = 0 und C = 0 -> 351748 Zeilen

Die Addition (A + B + C = 0) dauerte 5 Sekunden, während die logischen Bedingungen A = 0 und B = 0 und C = 0 11 Sekunden dauerten.

Auf der anderen Seite

Zurückgeben von Zeilen mit A <> 0 B <> 0 oder C <> 0 -> 3829750 Zeilen 58 Sekunden

Zeilen zurückgeben Wobei F65 + F67 + f64 <> 0 -> 3829750 Zeilen 57 Sekunden

Für den OP scheint es keinen signifikanten Unterschied zu geben.

Ich stimme gbn zu:

Wenn A -1 und B 1 ist, ist A + B = 0, aber A = 0 und B = 0 ist falsch

und mit AMtwo:

ABS (A) + ABS (B) + ABS (C) + ABS (D) ... Auch wenn Sie nur positive Werte erwarten und die Spalte negative Werte akzeptiert, sollten Sie davon ausgehen, dass Sie möglicherweise auf einen Wert stoßen

Die Ergebnisse sind sehr beeindruckend, wie ich dachte. Es scheint, dass die Addition viel schneller ist als die logischen Operatoren.

A = Float, B = Money und C = Float. Die verwendete Abfrage ist wie gezeigt. In meinem Fall sind alle positive Zahlen. Keine Indizes. In meinen Augen ist es nur logisch, dass die Hinzufügung schneller als die logischen Bedingungen ist!

JohnG
quelle
Sind diese Booleschen? Von wie vielen Spalten sprechen Sie (in den Beispielen) über 4 oder (im Titel) über 26? Es macht einen Unterschied. Welche Version von SQL Server? Wo kommen FLOAT und MONEY ins Spiel? Wie viele Zeilen nehmen wir an? Diese Frage hat eine Menge Faktoren.
Evan Carroll
@Evan Carroll Sie sind keine Booleschen Zahlen, sondern nicht indizierte Zahlen (int, float, money, etc). Unabhängig von der SQL-Version (SQL2012 und höher), der Anzahl der Zeilen oder Spalten, bestand die Frage darin, welcher Operator im Vergleich zu arithmetischen Operatoren eine bessere Leistung erbringt. Wie Sie sehen, demonstriert Max Vernon die Theorie mit seinen Beispielen perfekt.
JohnG

Antworten:

46

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 CHECKPOINTund DBCC DROPCLEANBUFFERSvor 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:

Bildbeschreibung hier eingeben

und die "diskrete Spalten" -Methode, die nach der ersten Zeile des Index suchen kann, in der die führende Indexspalte ANull ist:

Bildbeschreibung hier eingeben

Max Vernon
quelle
24

Angenommen, Sie haben einen Index für A, B, C und D. Könnte auch gefiltert werden.

Dies verwendet eher den Index als den Zusatz.

Where A=0 and B=0 and C=0 and D=0

In anderen Nachrichten ist, wenn A -1 und B 1 A+B=0ist, wahr, aber A=0 and B=0falsch.

gbn
quelle
7

(Bitte beachten Sie, dass diese Antwort gesendet wurde, bevor Tests in der Frage vermerkt wurden: Der Text der Frage endete direkt über dem Abschnitt mit den Testergebnissen .)

Ich würde vermuten , dass die einzelnen ANDBedingungen bevorzugt werden würde , da der Optimierer eher der Betrieb Kurzschluss wäre , wenn ein einziger von ihnen ist nicht gleich 0 ist , ohne dass zunächst eine Berechnung zu tun.

Da dies jedoch eine Frage der Leistung ist, sollten Sie zunächst einen Test einrichten, um die Antwort auf Ihre Hardware zu ermitteln . Melden Sie diese Ergebnisse mit Ihrem Testcode und bitten Sie andere, sich den Code anzusehen, um sicherzustellen, dass es sich um einen guten Test handelt. Möglicherweise gibt es noch andere Faktoren, über die Sie nicht nachgedacht haben.

Solomon Rutzky
quelle
3

Einige allgemeine Überlegungen: Wenn Sie keine Indizes zur Hand haben, ist es meines Erachtens unwichtig, welche der beiden von Ihnen gewählten Lösungen eine schlechte Leistung erbringt. Wenn Sie auf der anderen Seite einen Index für eine oder mehrere Spalten im Prädikat haben, ist die Leistung der ersten Spalte wahrscheinlich besser als die der zweiten, da die zweite wahrscheinlich nicht in der Lage ist, die Indizes zu verwenden.

Disjunctions (OR) schneidet im Allgemeinen schlechter ab als Conjunctions (AND), aber selbst wenn Sie eine Anfrage mit Disjunctions haben, werde ich mein Geld auf die erste setzen.

Lennart
quelle
2

Dies ist eine einfache Frage

Nein ist es nicht. Diese (Art) Frage plagt viele DBAs und Softwareentwickler Tag für Tag und ist alles andere als trivial.

dass ich keine Antwort zu finden scheine.

Ja, das wirst du nicht. Zumindest keine generelle Antwort. Zuallererst wird es sehr davon abhängen, welches RDBMS Sie verwenden (OK, Sie verwenden , aber immer noch). Es kann sich sogar ändern, wenn Sie von einer Version Ihres RDBMS zur nächsten wechseln.

Dann kann es von einer beliebigen Menge anderer kleiner Details abhängen, z. B. wie Ihre Datenbank die Daten speichert, wenn Sie Unterauswahlen / Verknüpfungen haben, die das Problem für das Planoptimierungsprogramm usw. verwirren. Das Optimierungsprogramm kann Ihnen je nach Ausführung unterschiedliche Pläne geben Auf wievielen Zeilen hast du ...

Ein realer Test ist normalerweise die einzig sinnvolle Möglichkeit, solche Fragen zu lösen. Außerdem werden Gewinne, die durch "arkane" Optimierungen wie diese erzielt werden, in der Regel durch eine intelligente Auswahl der Indizes verzehnfacht. Daher würde ich nicht zu viel Zeit darauf verwenden, bevor die Verwendung von Indizes wirklich ausgeschlossen wurde.

AnoE
quelle
0

Dies mag offensichtlich sein, aber wenn die Spalten Null sind INT, a+b+ckönnte dies auch dann gleich Null sein, wenn keine von ihnen tatsächlich Null ist. Sie testen zwei verschiedene Dinge!

Ross Presser
quelle
Ich habe gerade bemerkt, dass @gbn dies in seiner Antwort erwähnt hat.
Ross Presser