Ich schreibe in einem meiner nächsten Blog-Beiträge über Ranking- und aggregierte Fensterfunktionen, insbesondere die Segment- und Sequenzprojekt-Iteratoren. Ich verstehe es so, dass Segment Zeilen in einem Stream identifiziert, die das Ende / den Anfang einer Gruppe bilden, also die folgende Abfrage:
SELECT ROW_NUMBER() OVER (PARTITION BY someGroup ORDER BY someOrder)
Verwendet Segment, um festzustellen, wann eine Zeile zu einer anderen Gruppe als der vorherigen Zeile gehört. Der Sequenzprojekt-Iterator führt dann die tatsächliche Zeilennummernberechnung basierend auf der Ausgabe der Ausgabe des Segmentiterators durch.
Die folgende Abfrage, die diese Logik verwendet, sollte jedoch kein Segment enthalten müssen, da kein Partitionsausdruck vorhanden ist.
SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)
Wenn ich diese Hypothese versuche, verwenden diese beiden Abfragen jedoch einen Segmentoperator. Der einzige Unterschied besteht darin, dass für die zweite Abfrage kein GroupBy
Segment benötigt wird. Beseitigt das nicht in erster Linie die Notwendigkeit eines Segments?
Beispiel
CREATE TABLE dbo.someTable (
someGroup int NOT NULL,
someOrder int NOT NULL,
someValue numeric(8, 2) NOT NULL,
PRIMARY KEY CLUSTERED (someGroup, someOrder)
);
--- Query 1:
SELECT ROW_NUMBER() OVER (PARTITION BY someGroup ORDER BY someOrder)
FROM dbo.someTable;
--- Query 2:
SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)
FROM dbo.someTable;
quelle
<GroupBy />
sodass das Segment wirklich nichts tut. Fast gibt es die Segmentspalte an den Operator "Sequenzprojekt" aus. Der Grund dafür, dass der Segmentoperator dort ist, könnte sein, dass der Sequenzprojektoperator diesen Wert benötigt, um seine Arbeit zu erledigen.Antworten:
Ich fand diesen 6 Jahre alten Blog-Beitrag, der das gleiche Verhalten erwähnte.
Es sieht so aus
ROW_NUMBER()
, als ob immer ein Segmentoperator enthalten ist, unabhängig davon, ob erPARTITION BY
verwendet wird oder nicht. Wenn ich raten müsste, würde ich sagen, dass dies daran liegt, dass das Erstellen eines Abfrageplans für die Engine einfacher ist.Wenn das Segment in den meisten Fällen benötigt wird und in den Fällen, in denen es nicht benötigt wird, im Wesentlichen eine kostengünstige Nichtoperation ist, ist es viel einfacher, es einfach immer in den Plan aufzunehmen, wenn eine Fensterfunktion verwendet wird.
quelle
Gemäß showplan.xsd für den Ausführungsplan wird
GroupBy
ohneminOccurs
odermaxOccurs
Attribute angezeigt, die daher standardmäßig [1..1] verwenden, wodurch das Element obligatorisch und nicht unbedingt inhaltlich ist. Das untergeordnete ElementColumnReference
vom Typ (ColumnReferenceType
) hatminOccurs
0 und istmaxOccurs
unbegrenzt [0 .. *], was es optional macht , daher das zulässige leere Element. Wenn Sie manuell versuchen,GroupBy
den Plan zu entfernen und zu erzwingen, wird der erwartete Fehler angezeigt:Interessanterweise habe ich festgestellt, dass Sie den Segmentoperator manuell entfernen können, um einen gültigen Plan für das Forcen zu erhalten, der folgendermaßen aussieht:
Wenn Sie jedoch mit diesem Plan (unter Verwendung
OPTION ( USE PLAN ... )
) ausgeführt werden, wird der Segmentoperator auf magische Weise wieder angezeigt. Nur um zu zeigen, dass der Optimierer nur die XML-Pläne als grobe Richtlinie verwendet.Mein Prüfstand:
Hacken Sie den XML-Plan vom Prüfstand aus und speichern Sie ihn als .sqlplan, um den Plan abzüglich des Segments anzuzeigen.
PS Ich würde nicht zu viel Zeit damit verbringen, SQL-Pläne manuell zu durchforsten, als ob Sie mich kennen würden. Sie würden wissen, dass ich es als zeitaufwändige Arbeit betrachte und etwas, das ich niemals tun würde. Oh, warte!? :)
quelle