it-swarm.com.de

Beseitigen Sie die Schlüsselsuche im Ausführungsplan

Ich habe folgende Frage:

DECLARE @p__linq__0 UNIQUEIDENTIFIER

SET @p__linq__0 = '... some guid ...'

SELECT TOP 1
    [EventId] AS [EventId],       
    [DateCreated] AS [DateCreated],       
    [LocationId] AS [LocationId],       
    [SourceName] AS [SourceName],       
    [SourceState] AS [SourceState],       
    [Priority] AS [Priority],       
    [EventDescription] AS [EventDescription],       
    [FirstTrigger] AS [FirstTrigger]
FROM [dbo].[Watchdog]
WHERE 
    [LocationId] = @p__linq__0
    AND 
    [FirstTrigger] = 1
ORDER BY [DateCreated] DESC

Watchdog Tabelle definiert 2 Unabhängigkeiten:

  1. Clustered-Index für die Primärschlüsselspalte EventId
  2. Nicht gruppierter Index für die Spalte DateCreated

Dies ist der tatsächliche Ausführungsplan für die Abfrage: enter image description here

Lesen andere Beiträge zum Eliminieren der Schlüsselsuche Ich habe einen weiteren nicht gruppierten Index hinzugefügt, der alle Spalten von SELECT enthält.

CREATE NONCLUSTERED INDEX [LocationId_FirstTrigger] ON [dbo].[Watchdog]
(
    [LocationId] ASC,
    [FirstTrigger] ASC
)
INCLUDE (   [EventId],
    [DateCreated],
    [SourceName],
    [SourceState],
    [Priority],
    [EventDescription]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
GO

Dies hat jedoch nicht geholfen und der tatsächliche Ausführungsplan ist der gleiche. Wenn ich mir die Schlüsselsuche anschaue, ist die Ausgabe tatsächlich im neu hinzugefügten nicht gruppierten Index enthalten.

(enter image description here

Meine Frage ist, warum immer noch key lookup Statt Index-Scan/Suche ausgeführt wird.


[~ # ~] Update [~ # ~]

Nach einigen Vorschlägen in den Kommentaren habe ich den neu erstellten nicht gruppierten Index gelöscht und stattdessen den nicht gruppierten Index für die Spalte DateCreated einschließlich der Spalten von SELECT neu erstellt.

Der Ausführungsplan lautet nun wie folgt:

(enter image description here

Außerdem wurde die Ausführungszeit für Abfragen von mehr als 1 Minute auf wenige Sekunden gesenkt (diese Tabelle enthält mehr als 18 Millionen Zeilen).

Bedeutet dies, dass die Schlüsselsuche aufgrund von ORDER BY Für einen nicht gruppierten Index durchgeführt wurde?

6
Michael

Meine Frage ist, warum immer noch eine Schlüsselsuche statt Index-Scan/Suche durchgeführt wird.

Die Abfrage gibt an, dass die Ergebnisse nach DateCreated sortiert werden sollen. Da Sie bereits einen nicht gruppierten Index für DateCreated hatten, entschied das Optimierungsprogramm, dass die Kosten für die Suche nach Schlüsseln niedriger waren als für die Sortierung aller Daten nach DateCreated.

Bedeutet dies, dass die Schlüsselsuche aufgrund von ORDER BY für einen nicht gruppierten Index durchgeführt wurde?

Im Wesentlichen ja. Es wurde als billiger * angesehen, die Daten in der erforderlichen Reihenfolge zu lesen und zusätzliche Felder durch eine Schlüsselsuche abzurufen, anstatt alle Felder aus einem einzelnen Index zu lesen und sie dann nach DateCreated zu sortieren.

Sie können dies bestätigen, indem Sie die geschätzten Kosten zwischen vergleichen

  • die ursprüngliche Abfrage (mit den ursprünglichen Indizes) und
  • die ursprüngliche Abfrage mit einem Indexhinweis

Der Indexhinweis würde in der Zeile FROM folgendermaßen aussehen:

FROM [dbo].[Watchdog] WITH (INDEX (LocationId_FirstTrigger))

Dies sollte einen Plan ohne Schlüsselsuche (da LocationId_FirstTrigger Diese Abfrage abdeckt) und einen Sort -Operator erzeugen. Ich würde erwarten, dass die "geschätzten Kosten" höher sind, daher wurde der andere Plan gewählt.


* Um die Wahl des Optimierers hier zu erklären:

Die TOP (1) in Ihrer Abfrage bedeutet, dass der Optimierer ein Zeilenziel festlegt, was bedeutet, dass der Plan darauf ausgerichtet ist, schnell eine Zeile zu erstellen. Das Optimierungsprogramm erwartet, dass eine Zeile aus dem Index-Scan sehr schnell mit Ihrem LocationId-Prädikat übereinstimmt, da davon ausgegangen wird, dass die Werte gleichmäßig verteilt sind. Dies kann in der Realität wahr sein oder auch nicht. Die Kosten für eine Schlüsselsuche nach dem Index-Scan sind ziemlich gering.

Die Scan + Lookup-Option erscheint dem Optimierer daher billiger als das Finden von Übereinstimmungen mit LocationId_FirstTrigger Und Sortieren. Sie können die Zeilenziellogik für die Abfrage als Test deaktivieren, indem Sie einen OPTION (QUERYTRACEON 4138) - Hinweis hinzufügen. Sie werden wahrscheinlich feststellen, dass der Optimierer dann den Index LocationId_FirstTrigger Ohne Indexhinweis auswählt.

Die beste Alternative ist jedoch, Ihren Index zu ändern wie Mikael Eriksson vorschlägt .

7
Josh Darnell

Sie sollten die Spalte DateCreated in die Schlüsselspalten im Index LocationId_FirstTrigger Verschieben.

Dann erhalten Sie eine Suche nach LocationId und FirstTrigger und einen Rückwärtsscan des Index, um die Zeile mit dem höchsten Wert von DateCreated gemäß select top(1) ... order by DateCreated desc zu finden .

CREATE NONCLUSTERED INDEX [LocationId_FirstTrigger] ON [dbo].[Watchdog]
(
    [LocationId] ASC,
    [FirstTrigger] ASC,
    [DateCreated]
)
INCLUDE (   
    [EventId],
    [SourceName],
    [SourceState],
    [Priority],
    [EventDescription]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]

Wenn der Index nicht nach DateCreated sortiert ist, muss SQL Server alle übereinstimmenden Zeilen lesen und sortieren, um zu wissen, welche Zeile zurückgegeben werden soll.

6
Mikael Eriksson