Ich habe meine EXISTS-Schecks wie folgt geschrieben:
IF EXISTS (SELECT * FROM TABLE WHERE Columns=@Filters)
BEGIN
UPDATE TABLE SET ColumnsX=ValuesX WHERE Where Columns=@Filters
END
Einer der Datenbankadministratoren in einem früheren Leben sagte mir, wenn ich eine EXISTS
Klausel mache , benutze SELECT 1
stattSELECT *
IF EXISTS (SELECT 1 FROM TABLE WHERE Columns=@Filters)
BEGIN
UPDATE TABLE SET ColumnsX=ValuesX WHERE Columns=@Filters
END
Macht das wirklich einen Unterschied?
sql
sql-server
tsql
Raj Mehr
quelle
quelle
Antworten:
Nein, SQL Server ist intelligent und weiß, dass es für EXISTS verwendet wird, und gibt KEINE DATEN an das System zurück.
Quoth Microsoft: http://technet.microsoft.com/en-us/library/ms189259.aspx?ppud=4
Führen Sie Folgendes aus, um sich selbst zu überprüfen:
Wenn es tatsächlich etwas mit der SELECT-Liste machen würde, würde es einen div by zero-Fehler auslösen. Das tut es nicht.
BEARBEITEN: Beachten Sie, dass der SQL-Standard tatsächlich darüber spricht.
ANSI SQL 1992 Standard, S. 191 http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
quelle
EXISTS
Trick mit 1/0 kann sogar darauf ausgedehnt werdenSELECT 1 WHERE EXISTS(SELECT 1/0)
... scheint ein Schritt abstrakter zu sein, als der zweiteSELECT
keineFROM
Klausel hatSELECT COUNT(*) WHERE EXISTS(SELECT 1/0)
. EinSELECT
ohneFROM
in SQL Server wird so behandelt, als würde auf eine einzelnedual
Zeilentabelle zugegriffen (z. B. ähnlich wie bei der Auswahl aus der Tabelle in anderen RDBMS)SELECT
eine 1-Zeilen-Tabelle erstellt wird, bevor etwas anderes getan wird, obwohl der1/0
Müll die 1-Zeilen-Tabelle noch istEXISTS
?Der Grund für dieses Missverständnis liegt vermutlich in der Annahme, dass am Ende alle Spalten gelesen werden. Es ist leicht zu erkennen, dass dies nicht der Fall ist.
Gibt Plan
Dies zeigt, dass SQL Server den engsten verfügbaren Index verwenden konnte, um das Ergebnis zu überprüfen, obwohl der Index nicht alle Spalten enthält. Der Indexzugriff erfolgt unter einem Semi-Join-Operator. Dies bedeutet, dass der Scanvorgang beendet werden kann, sobald die erste Zeile zurückgegeben wird.
Es ist also klar, dass der obige Glaube falsch ist.
Conor Cunningham vom Query Optimiser-Team erklärt hier jedoch, dass er
SELECT 1
in diesem Fall normalerweise verwendet , da dies einen geringfügigen Leistungsunterschied bei der Kompilierung der Abfrage bewirken kann .Ich habe vier Möglichkeiten getestet, diese Abfrage in einer leeren Tabelle mit verschiedenen Spaltenzahlen auszudrücken.
SELECT 1
vsSELECT *
vsSELECT Primary_Key
vsSELECT Other_Not_Null_Column
.Ich habe die Abfragen in einer Schleife ausgeführt
OPTION (RECOMPILE)
und die durchschnittliche Anzahl von Ausführungen pro Sekunde gemessen. Ergebnisse untenWie zu sehen ist, gibt es keinen konsistenten Gewinner zwischen
SELECT 1
undSELECT *
und der Unterschied zwischen den beiden Ansätzen ist vernachlässigbar. DieSELECT Not Null col
undSELECT PK
erscheinen allerdings etwas schneller.Alle vier Abfragen beeinträchtigen die Leistung, wenn die Anzahl der Spalten in der Tabelle zunimmt.
Da die Tabelle leer ist, scheint diese Beziehung nur durch die Anzahl der Spaltenmetadaten erklärbar zu sein. Denn
COUNT(1)
es ist leicht zu erkennen, dass diesCOUNT(*)
irgendwann im Prozess von unten umgeschrieben wird.Welches gibt den folgenden Plan
Anhängen eines Debuggers an den SQL Server-Prozess und zufälliges Unterbrechen während der Ausführung des folgenden Vorgangs
Ich fand heraus, dass in den Fällen, in denen die Tabelle die meiste Zeit 1.024 Spalten enthält, der Aufrufstapel wie folgt aussieht, was darauf hinweist, dass er tatsächlich einen großen Teil der Zeit damit verbringt, Spaltenmetadaten zu laden, selbst wenn er
SELECT 1
verwendet wird (für den Fall, dass der Tabelle hat 1 Spalte zufällig gebrochen hat dieses Bit des Aufrufstapels in 10 Versuchen nicht getroffen)Dieses Handbuch Profilierungsversuch wird durch den VS 2012 Code - Profiler , die zeigt , eine ganz andere Auswahl von Funktionen raubend , die Kompilierung für die beiden Fälle (gesichert Top 15 Funktionen 1024 Spalten vs Top 15 Funktionen 1 Spalte ).
Sowohl die
SELECT 1
als auch dieSELECT *
Versionen überprüfen die Spaltenberechtigungen und schlagen fehl, wenn dem Benutzer nicht Zugriff auf alle Spalten in der Tabelle gewährt wird.Ein Beispiel, das ich aus einem Gespräch auf dem Haufen herausgeschnitten habe
Man könnte also spekulieren, dass der geringfügige offensichtliche Unterschied bei der Verwendung darin
SELECT some_not_null_col
besteht, dass nur die Berechtigungen für diese bestimmte Spalte überprüft werden (obwohl immer noch die Metadaten für alle geladen werden). Dies scheint jedoch nicht mit den Fakten übereinzustimmen, da die prozentuale Differenz zwischen den beiden Ansätzen kleiner wird, wenn die Anzahl der Spalten in der zugrunde liegenden Tabelle zunimmt.Auf jeden Fall werde ich nicht alle meine Abfragen in dieses Formular ändern, da der Unterschied sehr gering ist und nur während der Abfragekompilierung erkennbar ist. Das Entfernen des,
OPTION (RECOMPILE)
damit nachfolgende Ausführungen einen zwischengespeicherten Plan verwenden können, ergab Folgendes.Das von mir verwendete Testskript finden Sie hier
quelle
Der beste Weg, dies zu wissen, besteht darin, beide Versionen auf Leistung zu testen und den Ausführungsplan für beide Versionen zu überprüfen. Wählen Sie eine Tabelle mit vielen Spalten.
quelle
Es gibt keinen Unterschied in SQL Server und es war nie ein Problem in SQL Server. Der Optimierer weiß, dass sie gleich sind. Wenn Sie sich die Ausführungspläne ansehen, werden Sie feststellen, dass sie identisch sind.
quelle
Persönlich fällt es mir sehr, sehr schwer zu glauben, dass sie nicht auf denselben Abfrageplan optimieren. Die einzige Möglichkeit, in Ihrer speziellen Situation Bescheid zu wissen, besteht darin, sie zu testen. Wenn Sie dies tun, melden Sie sich bitte zurück!
quelle
Kein wirklicher Unterschied, aber es könnte einen sehr kleinen Leistungseinbruch geben. Als Faustregel sollten Sie nicht mehr Daten anfordern, als Sie benötigen.
quelle