Es ist eine einfache Auswahl aus einer temporären Tabelle, bei der eine vorhandene Tabelle auf ihrem Primärschlüssel verknüpft wird, wobei zwei Unterauswahlen unter Verwendung von Top 1 auf die verknüpfte Tabelle verweisen.
In Code:
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
JoinedTable.Col1,
JoinedTable.Col2,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2,
FROM
#TempTable as TempTable
LEFT JOIN
JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn1 AND
TempTable.PKColumn2 = JoinedTable.PKColumn2)
WHERE
JoinedTable.WhereColumn IN (1, 3)
Dies ist eine exakte Nachbildung meiner Anfrage.
Wenn ich die beiden Unterauswahlen entferne, läuft es gut und schnell. Mit den beiden Unterauswahlen erhalte ich ungefähr 100 Datensätze pro Sekunde, was für diese Abfrage extrem langsam ist, da fast eine Million Datensätze zurückgegeben werden sollten.
Ich habe überprüft, ob jede Tabelle einen Primärschlüssel hat, das tun sie alle. Sie alle haben Indizes UND Statistiken für ihre wichtigen Spalten, wie die in den WHERE-Klauseln und die in der JOIN-Klausel. Die einzige Tabelle, in der weder ein Primärschlüssel noch ein Index definiert ist, ist die temporäre Tabelle, aber es ist auch nicht das Problem, da es sich nicht um die Tabelle handelt, die sich auf die langsamen Unterauswahlen bezieht, und wie ich bereits erwähnt habe, läuft sie ohne Unterauswahlen einwandfrei.
Ohne TOP 1
diese gibt es mehr als ein Ergebnis zurück und löst einen Fehler aus.
Hilfe, jemand?
EDIT :
Der Ausführungsplan sagte mir also, dass mir ein Index fehlte. Ich habe es erstellt und einige der anderen Indizes neu erstellt. Nach einer Weile wurden sie vom Ausführungsplan verwendet, und die Abfrage wird jetzt schnell ausgeführt. Das einzige Problem ist, dass es mir nicht gelingt, dies auf einem anderen Server für dieselbe Abfrage erneut durchzuführen. Meine Lösung lautet also TIPP, welchen Index SQL Server verwenden wird.
Antworten:
Ich denke, bei einer Abfrage von Millionen Datensätzen muss man Dinge wie vermeiden
OUTER JOINS
. Ich schlage vor, Sie verwendenUNION ALL
anstelle vonLEFT JOIN
. Solange ich denkeCROSS APPLY
, dass dies effizienter ist als eine Unterabfrage in der select-Klausel, werde ich die von Conard Frix geschriebene Abfrage ändern, was ich für richtig halte.Jetzt: Als ich anfing, Ihre Abfrage zu ändern, bemerkte ich, dass Sie eine WHERE-Klausel haben, die besagt :
JoinedTable.WhereColumn IN (1, 3)
. In diesem Fall wird die Bedingung falsch, wenn das Feld null ist. Warum verwenden Sie dann LEFT JOIN, während Sie nullwertige Zeilen filtern? ersetzen Sie einfachLEFT JOIN
mitINNER JOIN
, ich garantiere , dass es schneller zu machen.über INDEX:
Bitte beachten Sie, dass Sie beispielsweise einen Index für eine Tabelle haben
und Ihr Index ist:
und du willst so etwas machen:
Sie haben die Spalte nicht in Ihren Index aufgenommen.
b
Was passiert also?Wenn SQL-Server Ihren Index verwendet, wird es in dem Index durchsuchen, die so genannten „Index Seek“ und dann auf Haupttabelle bezieht sich auf Spalte zu erhalten
b
, die so genannten „Look Up“ . Dieser Vorgang kann viel länger dauern als das Scannen der Tabelle selbst: "Tabellenscan" .Basierend auf den Statistiken, über die SQL Server verfügt, wird Ihr Index in solchen Situationen möglicherweise überhaupt nicht verwendet.
Überprüfen Sie daher zunächst
Execution Plan
, ob der Index überhaupt verwendet wird.Wenn ja oder nein, ändern Sie Ihren Index so, dass er alle von Ihnen ausgewählten Spalten enthält. sag wie:
In diesem Fall wird Look Up nicht benötigt und Ihre Abfrage wird viel schneller ausgeführt.
quelle
Es ist die Unterauswahl in Ihrer Spaltenauswahl, die die langsame Rückkehr verursacht. Sie sollten versuchen, Ihre Unterauswahl in linken Verknüpfungen zu verwenden, oder eine abgeleitete Tabelle verwenden, wie ich unten definiert habe.
Verwenden von Linksverknüpfungen zu zwei Instanzen der dritten Tabelle
Verwenden einer abgeleiteten Tabelle
quelle
Versuchen Sie stattdessen ein Kreuz anzuwenden
Sie können auch CTEs und row_number oder eine Inline-Abfrage mit MIN verwenden
quelle
Verschieben Sie die JOIN-Bits aus dem Hauptteil der Klausel und setzen Sie sie als Unterauswahl. Wenn Sie es in den Abschnitt WHERE and JOIN verschieben, müssen Sie nicht immer wieder TOP 1 AUSWÄHLEN, was meiner Meinung nach der Grund für die Langsamkeit ist. Wenn Sie dies überprüfen möchten, überprüfen Sie den Ausführungsplan.
quelle
Die
ThirdTable
Referenzen (Unterauswahl in Ihrem Beispiel) benötigen dieselbe Indexaufmerksamkeit wie jeder andere Teil einer Abfrage.Unabhängig davon, ob Sie Unterauswahl verwenden:
LINKE VERBINDUNGEN (wie von John Hartsock vorgeschlagen):
CROSS APPLY (wie von Conrad Frix vorgeschlagen):
Sie müssen sicherstellen
covering indexes
, dass fürThirdTable.SomeColumn
und definiert sindThirdTable.SomeOtherColumn
und die Indizes eindeutig sind. Dies bedeutet, dass Sie dieThirdTable
Referenzen weiter qualifizieren müssen , um die Auswahl mehrerer Zeilen zu vermeiden und die Leistung zu verbessern. Die Wahlsub selects
,LEFT JOIN
oderCROSS APPLY
nicht wirklich eine Rolle , bis Sie die Selektivität für verbessernThirdTable.SomeColumn
undThirdTable.SomeOtherColumn
um mehr Spalten einschließlich einzigartige Selektivität zu gewährleisten. Bis dahin gehe ich davon aus, dass Ihre Leistung weiterhin darunter leiden wird.Das
covering index
Thema wird von Maziar Taheri gut vorgestellt; Obwohl ich seine Arbeit nicht wiederhole, betone ich die Notwendigkeit, die Verwendung von Deckungsindizes zu Herzen zu nehmen.Kurz gesagt: Verbessern Sie die Selektivität für die
ThirdTable.SomeColumn
undThirdTable.SomeOtherColumn
Abfragen (oder Verknüpfungen), indem Sie verwandte Tabellenspalten hinzufügen, um eine eindeutige Zeilenübereinstimmung sicherzustellen. Wenn dies nicht möglich ist, treten weiterhin Leistungsprobleme auf, da der Motor damit beschäftigt ist, Reihen einzuziehen, die anschließend weggeworfen werden. Dies wirkt sich auf Ihre E / A, CPU und letztendlich auf den Ausführungsplan aus.quelle