Grundlagen des Ausführungsplans - Verwirrung um Hash-Übereinstimmungen

39

Ich fange an, Ausführungspläne zu lernen und bin verwirrt darüber, wie genau ein Hash-Match funktioniert und warum es in einem einfachen Join verwendet wird:

select Posts.Title, Users.DisplayName
From Posts JOIN Users on
Posts.OwnerUserId = Users.Id
OPTION (MAXDOP 1)

Bildbeschreibung hier eingeben

Soweit ich weiß, werden die Ergebnisse des Top-Index-Scans zum Hash und jede Zeile im unteren Index-Cluster-Scan wird nachgeschlagen. Ich verstehe, wie Hash-Tabellen zumindest zu einem gewissen Grad funktionieren, bin jedoch verwirrt darüber, welche Werte in einem Beispiel wie diesem genau gehasht werden.

Was für mich Sinn machen würde, ist das gemeinsame Feld zwischen ihnen, die ID, ist gehasht - aber wenn dies der Fall ist, warum ist eine Zahl gehasht?

Kyle Brandt
quelle

Antworten:

29

Als Antwort zitiert SQLRockstar

Am besten für große, unsortierte Eingaben.

Jetzt,

  • Aus dem Users.DisplayName-Indexscan (angenommen, nicht gruppiert) erhalten Sie Users.Id (angenommen, gruppiert) = unsortiert
  • Sie durchsuchen außerdem Posts nach OwnerUserId = unsortiert

Dies sind 2 ungeordnete Eingänge.

Ich würde einen Index für die Posts-Tabelle auf OwnerUserId einschließlich Titel in Betracht ziehen. Dies fügt dem JOIN +, das den Index abdeckt, eine gewisse Reihenfolge auf einer Seite der Eingabe hinzu

CREATE INDEX IX_OwnerUserId ON Posts (OwnerUserId) INCLUDE (Title)

Möglicherweise stellen Sie dann fest, dass der Index Users.DisplayName nicht verwendet wird und stattdessen die PK durchsucht wird.

gbn
quelle
1
Ah okay, ich sehe jetzt, ich dachte an die Users.DisplayName wurde von der PK bestellt, was einfach nicht der Fall ist. Jetzt ist die Verwendung von Hash für mich viel sinnvoller. Vielen Dank!
Kyle Brandt
1
Sie können auch den OPTION (FAST n)Hinweis versuchen , wobei n die ungefähre Anzahl der zu erwartenden Zeilen ist. Dies führt dazu, dass der Optimierer eher auf verschachtelte Schleifen als auf Hash-Verknüpfungen ausgerichtet wird, wenn n niedrig ist. Der Grund dafür ist, dass Hash-Joins für große Joins schnell sind, aber hohe Startkosten verursachen. Verschachtelte Schleifen sind pro Zeile teuer, können aber sehr billig gestartet werden. Es ist also eine Frage der Feinabstimmung basierend auf Ihren tatsächlichen Daten und Zugriffsmustern.
Gaius
1
@Gaius: Ich persönlich hätte lieber Indizes als Hinweise. Ein Hinweis ist nur dann gut für die Abfrage, wenn Sie ihn hinzufügen. Aka der Hinweis wird eine Haftung im Laufe der Zeit. Indizes sind in der Regel viel länger nützlich.
28.
1
Es ist kein Entweder-Oder-Vorschlag :-)
Gaius
14

Von http://sqlinthewild.co.za/index.php/2007/12/30/execution-plan-operations-joins/

"Die Hash-Verknüpfung ist eine der teureren Verknüpfungsoperationen, da für die Verknüpfung eine Hash-Tabelle erstellt werden muss. Die Verknüpfung eignet sich jedoch am besten für große, unsortierte Eingaben. Sie ist die speicherintensivste von allen der Joins

Beim Hash-Join wird zuerst eine der Eingaben gelesen und die Join-Spalte gehasht. Der resultierende Hash und die Spaltenwerte werden in eine im Speicher erstellte Hash-Tabelle eingefügt. Dann werden alle Zeilen in der zweiten Eingabe gelesen, diese gehasht und die Zeilen im resultierenden Hash-Bucket auf die verbindenden Zeilen überprüft. "

welche Links zu diesem Beitrag:

http://blogs.msdn.com/b/craigfr/archive/2006/08/10/687630.aspx

HTH

SQLRockstar
quelle
Wenn es sich also nur um die ID-Felder handelt, verstehe ich den Vorteil des Hashens eines ID-Felds wohl nicht?
Kyle Brandt
+1 für den Link zu Craig Freedmans Blog gibt es weitere Beitrittsartikel: blogs.msdn.com/b/craigfr/archive/tags/joins
Jeff
9

Das Hashing eines numerischen Felds hat den Vorteil, dass Sie einen größeren Wert in kleinere Teile zerlegen, damit er in eine Hash-Tabelle passt.

So beschreibt es Grant Fritchey:

Eine Hash-Tabelle ist andererseits eine Datenstruktur, die alle Elemente in gleich große Kategorien oder Buckets unterteilt, um einen schnellen Zugriff auf die Elemente zu ermöglichen. Die Hash-Funktion bestimmt, in welchen Bucket sich ein Element befindet können Sie eine Zeile aus einer Tabelle nehmen, sie in einen Hash-Wert hacken und dann den Hash-Wert in einer Hash-Tabelle speichern. "

Sie können auch eine kostenlose Kopie seines eBooks "Auflösen von SQL Server-Ausführungsplänen" über einen Link aus dem folgenden Artikel erhalten:

Quelle: http://www.simple-talk.com/sql/performance/graphical-execution-plans-for-simple-sql-queries/

Jeff
quelle
Eine weitere interessante Artikelserie zu JOINS: sql-server-performance.com/articles/dba/…
Jeff
Ich arbeite auf meine Art und Weise daran, SQL Server-Ausführungspläne zu zerlegen - es ist großartig! Aber ich bin in diesem Punkt ein wenig hängen geblieben :-P
Kyle Brandt