Bei SQL Server ist ein interessantes Problem aufgetreten. Betrachten Sie das folgende Reprobeispiel:
CREATE TABLE #test (s_guid uniqueidentifier PRIMARY KEY);
INSERT INTO #test (s_guid) VALUES ('7E28EFF8-A80A-45E4-BFE0-C13989D69618');
SELECT s_guid FROM #test
WHERE s_guid = '7E28EFF8-A80A-45E4-BFE0-C13989D69618'
AND s_guid <> NEWID();
DROP TABLE #test;
Bitte vergessen Sie für einen Moment, dass die s_guid <> NEWID()
Bedingung völlig unbrauchbar zu sein scheint - dies ist nur ein minimales Repro-Beispiel. Da die Wahrscheinlichkeit, NEWID()
mit einem bestimmten konstanten Wert übereinzustimmen, äußerst gering ist, sollte der Wert jedes Mal WAHR sein.
Aber das tut es nicht. Das Ausführen dieser Abfrage gibt normalerweise 1 Zeile zurück, aber manchmal (ziemlich häufig, mehr als 1 Mal von 10) werden 0 Zeilen zurückgegeben. Ich habe es mit SQL Server 2008 auf meinem System reproduziert, und Sie können es online mit der oben verlinkten Geige reproduzieren (SQL Server 2014).
Ein Blick auf den Ausführungsplan zeigt, dass der Abfrageanalysator die Bedingung anscheinend aufteilt in s_guid < NEWID() OR s_guid > NEWID()
:
... was vollständig erklärt, warum es manchmal fehlschlägt (wenn die erste generierte ID kleiner und die zweite größer als die angegebene ID ist).
Ist SQL Server zu bewerten erlaubt A <> B
wie A < B OR A > B
, auch wenn einer der Ausdrücke ist nicht deterministisch ? Wenn ja, wo ist es dokumentiert? Oder haben wir einen Bug gefunden?
Interessanterweise AND NOT (s_guid = NEWID())
ergibt sich der gleiche Ausführungsplan (und das gleiche zufällige Ergebnis).
Wir haben dieses Problem gefunden, als ein Entwickler eine bestimmte Zeile optional ausschließen und Folgendes verwenden wollte:
s_guid <> ISNULL(@someParameter, NEWID())
als "Abkürzung" für:
(@someParameter IS NULL OR s_guid <> @someParameter)
Ich suche nach Dokumentation und / oder Bestätigung eines Fehlers. Der Code ist nicht allzu relevant, sodass keine Problemumgehungen erforderlich sind.
quelle
Antworten:
Dies ist ein etwas kontroverser Punkt, und die Antwort ist ein qualifiziertes "Ja".
Die beste Diskussion, die mir bekannt ist, wurde als Antwort auf Itzik Ben-Gans Connect-Fehlerbericht Bug with NEWID and Table Expressions gegeben , der geschlossen wurde, da er nicht behoben werden konnte. Connect wurde inzwischen eingestellt, sodass der Link zu einem Webarchiv besteht. Leider ging durch den Niedergang von Connect viel nützliches Material verloren (oder war schwerer zu finden). Wie auch immer, die nützlichsten Zitate von Jim Hogg von Microsoft sind:
Ein Beispiel für die Änderung des Verhaltens in dieser Hinsicht im Laufe der Zeit ist, dass NULLIF mit nicht deterministischen Funktionen wie RAND () nicht korrekt funktioniert . Es gibt auch andere ähnliche Fälle, in denen z. B.
COALESCE
eine Unterabfrage verwendet wird, die zu unerwarteten Ergebnissen führen kann und die ebenfalls schrittweise behandelt werden.Jim fährt fort:
Dies ist eine Folge der Normalisierung, die sehr früh während der Abfragekompilierung auftritt. Beide Ausdrücke werden in genau dieselbe normalisierte Form kompiliert, sodass derselbe Ausführungsplan erstellt wird.
quelle
Dies wird hier dokumentiert:
Benutzerdefinierte Funktionen
Dies ist nicht das einzige Abfrageformular, in dem der Abfrageplan NEWID () mehrmals ausführt und das Ergebnis ändert. Dies ist verwirrend, aber tatsächlich wichtig, damit NEWID () für die Schlüsselerzeugung und die zufällige Sortierung nützlich ist.
Am verwirrendsten ist, dass sich nicht alle nicht deterministischen Funktionen tatsächlich so verhalten. Beispielsweise werden RAND () und GETDATE () nur einmal pro Abfrage ausgeführt.
quelle
=
,<
und>
kann effizient gegen einen BTree ausgewertet werden.Wenn Sie sich dieses alte SQL 92-Standarddokument ansehen , werden die Anforderungen bezüglich der Ungleichung im Abschnitt "
8.2 <comparison predicate>
" wie folgt beschrieben:Hinweis: Ich habe der Vollständigkeit halber 7b und 7h eingefügt, da es sich um
<>
Vergleiche handelt. Ich glaube nicht, dass der Vergleich von Zeilenwertkonstruktoren mit mehreren Werten in T-SQL implementiert ist, es sei denn, ich verstehe massiv falsch, was dies sagt - was durchaus möglich istDas ist ein Haufen verwirrenden Mülls. Aber wenn Sie weiter auf dem Müll tauchen wollen ...
Ich denke, dass 1.ii das Element ist, das in diesem Szenario angewendet wird, da wir die Werte von "Zeilenwertkonstruktorelementen" vergleichen.
Grundsätzlich
X <> Y
gilt, wenn die durch X und Y dargestellten Werte nicht gleich sind. DaX < Y OR X > Y
es sich um eine logisch äquivalente Umschreibung dieses Prädikats handelt, ist es für den Optimierer absolut cool, diese zu verwenden.Der Standard legt für diese Definition keine Einschränkungen in Bezug auf die Deterministik (oder was auch immer Sie daraus ableiten) der Zeilenwertkonstruktorelemente auf beiden Seiten des
<>
Vergleichsoperators fest. Es liegt in der Verantwortung des Benutzercodes, mit der Tatsache umzugehen, dass ein Werteausdruck auf einer Seite möglicherweise nicht deterministisch ist.quelle