it-swarm.com.de

Ersetzen Sie die lange GROUP BY-Liste durch eine Unterabfrage

Dies ist ein Repost meiner Frage zum Stapelüberlauf. Sie schlugen vor, es hier zu fragen:

Ich habe einen Online-Artikel aus dem Jahr 2005 gefunden, in dem der Autor behauptet, dass viele Entwickler GROUP BY falsch verwenden und dass Sie ihn besser durch eine Unterabfrage ersetzen sollten.

Ich habe es bei einer meiner Abfragen getestet, bei der ich das Ergebnis einer Suche nach der Anzahl der verknüpften Einträge aus einer anderen Tabelle sortieren muss (häufigere Einträge sollten zuerst angezeigt werden). Mein ursprünglicher, klassischer Ansatz bestand darin, beide Tabellen auf einer gemeinsamen ID zu verknüpfen, nach jedem Feld in der Auswahlliste zu gruppieren und das Ergebnis nach der Anzahl der Untertabellen zu ordnen.

Jeff Smith vom verlinkten Blog behauptet nun, dass Sie besser eine Unterauswahl verwenden sollten, die die gesamte Gruppierung übernimmt, als sich dieser Unterauswahl anzuschließen. Bei der Überprüfung der Ausführungspläne beider Ansätze stellt SSMS fest, dass die große Gruppe 52% der Zeit und die Unterauswahl 48% benötigt. Aus technischer Sicht scheint der Unterauswahlansatz tatsächlich geringfügig schneller zu sein. Der "verbesserte" SQL-Befehl scheint jedoch einen komplizierteren Ausführungsplan zu generieren (in Bezug auf Knoten).

Was denken Sie? Können Sie mir einige Details dazu geben, wie die Ausführungspläne in diesem speziellen Fall zu interpretieren sind und welche im Allgemeinen die bevorzugte Option ist?

SELECT
    a.ID,
    a.ID_AddressType,
    a.Name1,
    a.Name2,
    a.Street,
    a.Number,
    a.ZipCode,
    a.City,
    a.Country
FROM dbo.[Address] a
INNER JOIN CONTAINSTABLE(
    dbo.[Address],
    FullAddress,
    '"ZIE*"',
    5
) s ON a.ID = s.[KEY]
LEFT JOIN dbo.Haul h ON h.ID_DestinationAddress = a.ID
GROUP BY
    a.ID,
    a.ID_AddressType,
    a.Name1,
    a.Name2,
    a.Street,
    a.Number,
    a.ZipCode,
    a.City,
    a.Country,
    s.RANK
ORDER BY s.RANK DESC, COUNT(*) DESC;

SELECT
    a.ID,
    a.ID_AddressType,
    a.Name1,
    a.Name2,
    a.Street,
    a.Number,
    a.ZipCode,
    a.City,
    a.Country
FROM dbo.[Address] a
INNER JOIN CONTAINSTABLE(
    dbo.[Address],
    FullAddress,
    '"ZIE*"',
    5
) s ON a.ID = s.[KEY]
LEFT JOIN (
    SELECT ID_DestinationAddress, COUNT(*) Cnt
    FROM dbo.Haul
    GROUP BY ID_DestinationAddress
) h ON h.ID_DestinationAddress = a.ID
ORDER BY s.RANK DESC, h.Cnt DESC;

(enter image description here

8
André Reichelt

Wenn Sie den linken Join mit dbo.Haul In eine Unterabfrage ändern, werden diese unterschiedlichen Werte von ID_DestinationAddress (Stream Aggregate) berechnet und direkt nach Abrufen der Daten aus dem Scan gezählt (Skalar berechnen).

Folgendes sehen Sie im Ausführungsplan:

(enter image description here

Bei Verwendung der Methode GROUP BY Wird die Gruppierung nur durchgeführt, nachdem Daten, die durch die linke Verknüpfung zwischen dbo.Haul Und dbo.[Address] Übertragen wurden.

(enter image description here

Wie viel besser es ist, hängt vom eindeutigen Werteverhältnis von dbo.Haul ab. Weniger eindeutige Werte bedeuten ein besseres Ergebnis für den zweiten Ausführungsplan, da der linke Join weniger Werte verarbeiten muss.

Das andere positive Ergebnis der zweiten Abfrage ist, dass nur die Eindeutigkeit von ID_DestinationAddress Berechnet wird, nicht die Eindeutigkeit aller Spalten als Ganzes in der Gruppe von.

Auch hier sollten Sie die Ergebnisse für Ihre Abfrage, Ihren Datensatz und Ihre Indizes testen und validieren. Eine Möglichkeit zu testen, ob Sie mit Ausführungsplänen nicht vertraut sind, besteht darin, SET STATISTICS IO, TIME ON; Vor dem Ausführen der Abfragen festzulegen und diese Laufzeitstatistiken besser lesbar zu machen, indem Sie sie in ein Tool wie statisticsparser einfügen.


Testen

Ein kleiner Test, um zu zeigen, welche Datenunterschiede für diese Abfragen gelten können.

Wenn die Tabelle dbo.Haul Nicht viele Übereinstimmungen mit den 5 Datensätzen aufweist, die von der FULLTEXT-Indexfilterung zurückgegeben werden, ist der Unterschied nicht so groß:

Nach Abfrageplan gruppieren

nterabfrage-Abfrageplan

1000 Zeilen könnten früher gefiltert werden, aber die Ausführungszeit beträgt für beide Abfragen auf meinem Computer ohnehin ungefähr 15 ms .

Wenn ich nun meine Daten so ändere, dass diese 5 Datensätze viel mehr Übereinstimmungen mit dbo.Haul Auf der linken Seite haben, verbinden Sie:

Der Unterschied zwischen dem Gruppe nach Abfrageenter image description here

    <QueryTimeStats CpuTime="1564" ElapsedTime="1566" />

Und die nterabfrage wird klarer

(enter image description here

und die Statistiken:

<QueryTimeStats CpuTime="680" ElapsedTime="690"/>
8
Randi Vertongen