Wie kann ich einen Key Lookup (Clustered) -Operator in meinem Ausführungsplan entfernen?
Die Tabelle hat tblQuotes
bereits einen Clustered-Index (on QuoteID
) und 27 Nonclustered-Indizes, daher versuche ich, keine weiteren zu erstellen.
Ich habe die Clustered-Index-Spalte QuoteID
in meine Abfrage eingefügt, in der Hoffnung, dass sie hilft - aber leider immer noch dieselbe.
Oder sehen Sie es sich an:
Dies sagt der Key Lookup-Operator:
Abfrage:
declare
@EffDateFrom datetime ='2017-02-01',
@EffDateTo datetime ='2017-08-28'
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
IF OBJECT_ID('tempdb..#Data') IS NOT NULL
DROP TABLE #Data
CREATE TABLE #Data
(
QuoteID int NOT NULL, --clustered index
[EffectiveDate] [datetime] NULL, --not indexed
[Submitted] [int] NULL,
[Quoted] [int] NULL,
[Bound] [int] NULL,
[Exonerated] [int] NULL,
[ProducerLocationId] [int] NULL,
[ProducerName] [varchar](300) NULL,
[BusinessType] [varchar](50) NULL,
[DisplayStatus] [varchar](50) NULL,
[Agent] [varchar] (50) NULL,
[ProducerContactGuid] uniqueidentifier NULL
)
INSERT INTO #Data
SELECT
tblQuotes.QuoteID,
tblQuotes.EffectiveDate,
CASE WHEN lstQuoteStatus.QuoteStatusID >= 1 THEN 1 ELSE 0 END AS Submitted,
CASE WHEN lstQuoteStatus.QuoteStatusID = 2 or lstQuoteStatus.QuoteStatusID = 3 or lstQuoteStatus.QuoteStatusID = 202 THEN 1 ELSE 0 END AS Quoted,
CASE WHEN lstQuoteStatus.Bound = 1 THEN 1 ELSE 0 END AS Bound,
CASE WHEN lstQuoteStatus.QuoteStatusID = 3 THEN 1 ELSE 0 END AS Exonareted,
tblQuotes.ProducerLocationID,
P.Name + ' / '+ P.City as [ProducerName],
CASE WHEN tblQuotes.PolicyTypeID = 1 THEN 'New Business'
WHEN tblQuotes.PolicyTypeID = 3 THEN 'Rewrite'
END AS BusinessType,
tblQuotes.DisplayStatus,
tblProducerContacts.FName +' '+ tblProducerContacts.LName as Agent,
tblProducerContacts.ProducerContactGUID
FROM tblQuotes
INNER JOIN lstQuoteStatus
on tblQuotes.QuoteStatusID=lstQuoteStatus.QuoteStatusID
INNER JOIN tblProducerLocations P
On P.ProducerLocationID=tblQuotes.ProducerLocationID
INNER JOIN tblProducerContacts
ON dbo.tblQuotes.ProducerContactGuid = tblProducerContacts.ProducerContactGUID
WHERE DATEDIFF(D,@EffDateFrom,tblQuotes.EffectiveDate)>=0 AND DATEDIFF(D, @EffDateTo, tblQuotes.EffectiveDate) <=0
AND dbo.tblQuotes.LineGUID = '6E00868B-FFC3-4CA0-876F-CC258F1ED22D'--Surety
AND tblQuotes.OriginalQuoteGUID is null
select * from #Data
Ausführungsplan:
Antworten:
Wichtige Suchvorgänge verschiedener Varianten treten auf, wenn der Abfrageprozessor Werte aus Spalten abrufen muss, die nicht im Index gespeichert sind, der zum Auffinden der Zeilen verwendet wird, die für die Abfrage erforderlich sind, um Ergebnisse zurückzugeben.
Nehmen Sie zum Beispiel den folgenden Code, in dem wir eine Tabelle mit einem einzelnen Index erstellen:
Wir werden 1.000.000 Zeilen in die Tabelle einfügen, damit wir mit einigen Daten arbeiten können:
Jetzt werden wir die Daten mit der Option abfragen, den "tatsächlichen" Ausführungsplan anzuzeigen:
Der Abfrageplan zeigt:
Die Abfrage untersucht den
IX_Table1
Index, um die Zeile zu finden,Table1ID = 5000000
da das Betrachten dieses Index viel schneller ist als das Durchsuchen der gesamten Tabelle nach diesem Wert. Um die Abfrageergebnisse zu erfüllen, muss der Abfrageprozessor jedoch auch den Wert für die anderen Spalten in der Tabelle finden. Hier kommt die "RID-Suche" ins Spiel. In der Tabelle wird nach der Zeilen-ID (der RID in der RID-Suche)Table1ID
gesucht, die der Zeile mit dem Wert 500000 zugeordnet ist, und die Werte aus derTable1Data
Spalte abgerufen . Wenn Sie mit der Maus über den Knoten "RID-Suche" im Plan fahren, wird Folgendes angezeigt:Die "Ausgabeliste" enthält die von der RID-Suche zurückgegebenen Spalten.
Ein interessantes Beispiel ist eine Tabelle mit einem Clustered-Index und einem Nicht-Clustered-Index. Die folgende Tabelle enthält drei Spalten. ID ist der Clustering-Schlüssel,
Dat
der durch einen nicht gruppierten Index indiziert wirdIX_Table
, und eine dritte SpalteOth
.Nehmen Sie diese Beispielabfrage:
Wir bitten SQL Server, jede Spalte aus der Tabelle zurückzugeben, in der die
Dat
Spalte das Wort enthältTest
. Wir haben hier ein paar Möglichkeiten; Wir können uns die Tabelle ansehen (dh den Clustered-Index) - aber das würde das Scannen des gesamten Objekts bedeuten, da die Tabelle nachID
Spalten sortiert ist , was uns nichts darüber sagt, welche ZeilenTest
in derDat
Spalte enthalten sind. Die andere Option (und die von SQL Server ausgewählte) besteht darin, imIX_Table1
nicht gruppierten Index nach der Zeile zu suchen, in der SQL ServerDat = 'Test'
jedoch, da wir auch dieOth
Spalte benötigen , eine Suche im gruppierten Index mit einem "Schlüssel" durchführen muss Suchvorgang. Dies ist der Plan dafür:Wenn wir das nicht-gruppierten Index ändern , so dass es enthält die
Oth
Spalte:Führen Sie dann die Abfrage erneut aus:
Wir sehen jetzt eine einzelne nicht gruppierte Indexsuche, da SQL Server lediglich die Zeile
Dat = 'Test'
im Index suchen mussIX_Table1
, die den Wert fürOth
und den Wert für dieID
Spalte (den Primärschlüssel) enthält, die automatisch in jedem Nicht- Index vorhanden ist. Clustered-Index. Der Plan:quelle
Die Schlüsselsuche wird verursacht, weil die Engine einen Index verwendet hat, der nicht alle Spalten enthält, die Sie abrufen möchten. Der Index deckt also nicht die Spalten in der select- und where-Anweisung ab.
Um die Schlüsselsuche zu eliminieren, müssen Sie die fehlenden Spalten einschließen (die Spalten in der Ausgabeliste der Schlüsselsuche) = ProducerContactGuid, QuoteStatusID, PolicyTypeID und ProducerLocationID. Eine andere Möglichkeit besteht darin, die Abfrage zu zwingen, stattdessen den Clustered-Index zu verwenden.
Beachten Sie, dass 27 nicht gruppierte Indizes für eine Tabelle möglicherweise die Leistung beeinträchtigen. Beim Ausführen eines Updates, Einfügens oder Löschens muss SQL Server alle Indizes aktualisieren. Diese zusätzliche Arbeit kann sich negativ auf die Leistung auswirken.
quelle
Sie haben vergessen, das an dieser Abfrage beteiligte Datenvolumen anzugeben. Auch warum fügen Sie in eine temporäre Tabelle ein? Wenn Sie nur anzeigen müssen, führen Sie keine Einfügeanweisung aus.
Für die Zwecke dieser Abfrage gilt:
tblQuotes
keine 27 nicht gruppierten Indizes benötigt. Es benötigt 1 Clustered-Index und 5 Nicht-Clustered-Indizes oder vielleicht 6 Nicht-Clustered-Indexex.Diese Abfrage möchte Indizes für diese Spalten:
Ich habe auch den folgenden Code bemerkt:
ist
NON Sargable
also Indizes nicht nutzen können.Um diesen Code zu
SARgable
ändern , ändern Sie ihn wie folgt:Um Ihre Hauptfrage zu beantworten: "Warum erhalten Sie einen Schlüssel? Nachschlagen":
Sie erhalten,
KEY Look up
weil einige der in der Abfrage erwähnten Spalten nicht in einem Deckungsindex vorhanden sind.Sie können googeln und über
Covering Index
oder studierenInclude index
.In meinem Beispiel wird angenommen, dass tblQuotes.QuoteStatusID kein Clustered-Index ist, dann kann ich auch DisplayStatus abdecken. Da möchten Sie DisplayStatus in Resultset. Jede Spalte, die nicht in einem Index und in der Ergebnismenge vorhanden ist, kann zur Vermeidung abgedeckt werden
KEY Look Up or Bookmark lookup
. Dies ist ein Beispiel für den Index:** Haftungsausschluss: ** Denken Sie daran, dass oben nur mein Beispiel angezeigt wird. DisplayStatus kann nach der Analyse mit anderen Nicht-CIs abgedeckt werden.
Ebenso müssen Sie einen Index und einen Abdeckungsindex für die anderen an der Abfrage beteiligten Tabellen erstellen.
Sie bekommen
Index SCAN
auch in Ihren Plan.Dies kann passieren, weil kein Index in der Tabelle vorhanden ist oder wenn der Optimierer bei einem großen Datenvolumen lieber scannen als eine Indexsuche durchführen möchte.
Dies kann auch aufgrund von auftreten
High cardinality
. Erhalten Sie mehr Zeilen als erforderlich, da die Verknüpfung fehlerhaft ist. Dies kann auch korrigiert werden.quelle