Ich habe ein einfaches Skript, das vier Zufallszahlen (1 bis 4) abruft und sich dann wieder zusammenfügt, um die passende database_id-Nummer zu erhalten. Wenn ich das Skript mit LEFT JOIN ausführe, erhalte ich jedes Mal vier Zeilen zurück (das erwartete Ergebnis). Wenn ich es jedoch mit einem INNER JOIN ausführe, erhalte ich eine unterschiedliche Anzahl von Zeilen - manchmal zwei, manchmal acht.
Logischerweise sollte es keinen Unterschied geben, da ich weiß, dass Zeilen mit den Datenbank-IDs 1 bis 4 in sys.databases vorhanden sind. Und da wir aus der Zufallszahltabelle mit vier Zeilen auswählen (im Gegensatz zum Beitritt), sollten niemals mehr als vier Zeilen zurückgegeben werden.
Dies tritt sowohl in SQL Server 2012 als auch in 2014 auf. Warum gibt INNER JOIN eine unterschiedliche Anzahl von Zeilen zurück?
/* Works as expected -- always four rows */
SELECT rando.RandomNumber, d.database_id
FROM
(SELECT 1 + ABS(CHECKSUM(NEWID())) % (4) AS RandomNumber
FROM sys.databases WHERE database_id <= 4) AS rando
LEFT JOIN sys.databases d ON rando.RandomNumber = d.database_id;
/* Returns a varying number of rows */
SELECT rando.RandomNumber, d.database_id
FROM
(SELECT 1 + ABS(CHECKSUM(NEWID())) % (4) AS RandomNumber
FROM sys.databases WHERE database_id <= 4) AS rando
INNER JOIN sys.databases d ON rando.RandomNumber = d.database_id;
/* Also returns a varying number of rows */
WITH rando AS (
SELECT 1 + ABS(CHECKSUM(NEWID())) % (4) AS RandomNumber
FROM sys.databases WHERE database_id <= 4
)
SELECT r.RandomNumber, d.database_id
FROM rando AS r
INNER JOIN sys.databases d ON r.RandomNumber = d.database_id;
quelle
SELECT TOP (4) d.database_id FROM sys.databases AS d CROSS JOIN (VALUES (1),(2),(3),(4)) AS multi (i) WHERE d.database_id <= 4 ORDER BY CHECKSUM(NEWID()) ;
Ich denke, es funktioniert gut, weil es keinen Join für den Wert der nicht deterministischen Funktion gibt.Antworten:
Durch Hinzufügen des zusätzlichen SELECT wird die Bewertung des Berechnungsskalars tiefer in den Plan eingefügt und das Join-Prädikat angegeben. Der Berechnungsskalar oben verweist dann auf das frühere Prädikat.
Ich beschäftige mich immer noch mit dem Grund, warum es so spät ist, aber ich lese gerade diesen Beitrag von Paul White ( https://sql.kiwi/2012/09/compute-scalars-expressions-and-execution-plan-performance.html ) . Vielleicht hat es etwas damit zu tun, dass NEWID nicht deterministisch ist?
quelle
Dies könnte einige Einblicke geben, bis einer der klügeren Leute auf der Website eingreift.
Ich füge die zufälligen Ergebnisse in eine temporäre Tabelle ein und erhalte konstant 4 Ergebnisse, unabhängig vom Join-Typ.
Wenn ich Abfragepläne zwischen Ihrer zweiten Abfrage und der Variation mit einer Tabellenvariablen vergleiche, kann ich einen deutlichen Unterschied zwischen den beiden feststellen. Das rote X ist
No Join Predicate
so, dass es meinem Höhlenmenschen-Entwicklerhirn wirklich seltsam vorkommtWenn ich das zufällige Bit der Abfrage in einer Konstante
1 % (4)
eliminiere, sieht mein Plan besser aus, aber der Berechnungsskalar wurde eliminiert, sodass ich genauer hinschaueEs berechnet den Ausdruck für die Zufallszahl nach dem Join. Ob das erwartet wird, überlasse ich immer noch den internen Assistenten auf der Site, aber zumindest aus diesem Grund erhalten Sie variable Ergebnisse in Ihrem Join.
2014
Für diejenigen, die zu Hause mitspielen, wurden die obigen Abfragepläne aus einer 2008 R2-Instanz generiert. Die Pläne für 2014 sehen anders aus, aber der Vorgang "Skalar berechnen" bleibt nach dem Beitritt bestehen.
Dies ist der Abfrageplan für 2014 unter Verwendung des konstanten Ausdrucks
Dies ist der Abfrageplan für eine 2014-Instanz, die den Ausdruck newid verwendet.
Dies ist anscheinend beabsichtigt, Connect Problem hier. Vielen Dank an @paulWhite für das Wissen, dass es das gab.
quelle