Das Abfrageoptimierungsprogramm empfiehlt, einen Index hinzuzufügen, anstatt einen vorhandenen Index zu verwenden

7

Ich versuche herauszufinden, warum das Abfrageoptimierungsprogramm in SQL Server empfiehlt, einen neuen Index zu erstellen, anstatt einen vorhandenen Index zu verwenden, der für die Abfrage ausreichend zu sein scheint.

Zuerst den Tisch. Spaltennamen geändert, um die Unschuldigen zu schützen :-)

CREATE TABLE [myTable] (
  [id] [int] IDENTITY(1,1) NOT NULL,
  [serialNumber] [varchar](12) NOT NULL,
  [sName] [varchar](64) NOT NULL,
  [meanValue] [int] NOT NULL,
  [range] [int] NOT NULL,
  [modifiedDate] [datetime] NOT NULL,
  CONSTRAINT [PK_myTable] PRIMARY KEY CLUSTERED ( [id] ASC )
)

Erstellen Sie den betreffenden Index:

CREATE NONCLUSTERED INDEX [IDX_myIndex]
ON [myTable] ([serialNumber], [sName], [meanValue], [range])
INCLUDE ([modifiedDate])

Fügen Sie Daten zum Testen mit dem Generator Ihrer Wahl hinzu ;-) Führen Sie die folgende Abfrage aus (Tabelle enthält nur einige Millionen Datensätze)

SELECT TOP 1000
  [serialNumber],
  [sName],
  [meanValue],
  [range],
  [modifiedDate]
FROM [myTable]
WHERE [serialNumber] = 137802
AND [sName] = 'A Name'

Das Abfrageoptimierungsprogramm empfiehlt die Verwendung eines neuen Index, in dem die zusätzlichen where-Klauseln in INCLUDE anstelle eines Teils des Schlüssels behandelt werden:

CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[myTable] ([sName])
INCLUDE ([serialNumber],[meanValue],[range],[modifiedDate])

Ich hatte den Eindruck, dass ein breiterer Index, der mehr Spalten umfasst, als Index verwendet wird, solange die Reihenfolge der WHERE-Klauseln die Reihenfolge der indizierten Spalten darstellt.

Wenn ich auch WHERE auf den modifizierten Daten habe, wird der Index verwendet und der Abfrageoptimierer beschwert sich nicht:

SELECT TOP 1000
  [serialNumber],
  [sName],
  [meanValue],
  [range],
  [modifiedDate]
FROM [myTable]
WHERE [serialNumber] = 137802
AND [sName] = 'A Name'
AND ([modifiedDate] >= '2000-04-25' AND [modifiedDate] < '2019-04-30') 

Der DBA-Link
SQL Server 2008R2 - Warum mein Index nicht verwendet wird, deutet auf eine engere Korrelation zwischen dem Indexschlüssel hin und enthält die SELECT-Anweisung, um die Indexverwendung zu bestimmen (in meinem Beispiel sind sie jedoch im Grunde gleich). Ich habe viele Zeilen, die wahrscheinlich den Wahrscheinlichkeitstest für die Zeilenverwendung erfüllen, und es gibt keine NULL-Werte, wodurch der NULL-Effekt des Index negiert wird.

Ich dachte, vielleicht falsch, dass ein Index A, B, C, Deine Abfrage abdecken würde, wo A, B, Coder A, Boder ausgeführt Awürde. Ist diese Annahme falsch? Mir ist klar, dass es Randbedingungen geben könnte, die dieses Grundkonzept aus dem Gleichgewicht bringen, aber auf einer fundamentalen Ebene ist es nicht ungefähr so, wie es funktionieren soll?

Vielen Dank im Voraus für jede Hilfe, die auf die Dummheit in meinen Wegen hinweist und erkennt, dass ich (zurück) zur DB-Schule gehen muss usw. :-)

Hooligancat
quelle
3
Es gibt einen ziemlich großen Unterschied, die führende Schlüsselspalte in einem Index ist SerialNumberund die andere ist sName. Auch in Fällen, in denen zwei Indizes eine Abfrage gleichermaßen erfüllen könnten und die Indizes im Wesentlichen dieselbe Größe haben, ist dies im Wesentlichen ein Münzwurf für SQL Server. Die Tatsache, dass ein anderer Index empfohlen wurde, bedeutet wahrscheinlich, dass ein anderer Plan verwendet werden könnte (dies ist nur ein Kommentar, da ich nicht in die tatsächlichen Details geschaut oder versucht habe, Ihr Szenario zu wiederholen).
Aaron Bertrand
Ihre Annahme, ob der Index abgedeckt wird oder nicht, ist eine korrekte Annahme. Aber wie Herr Bertrand sagt, könnte die Kardinalität von SerialNumber vs sName einen Index für eine bestimmte Abfrage weitaus nützlicher machen als einen anderen, selbst wenn beide Indizes die Abfrage abdecken.
mskinner
Können Sie auch klarstellen? Wird die Empfehlung außer Acht gelassen, wird sie IDX_myIndexnicht verwendet? Was ist der eigentliche Abfrageplan?
Ypercubeᵀᴹ
Sie haben auch, WHERE [serialNumber] = 137802während die Spalte ein Varchar ist. Ich wette, das ist der Grund für die Beschwerden.
Ypercubeᵀᴹ
2
Warum ist serialNumbera überhaupt, varcharwenn die darin enthaltenen Werte numerisch sind? Wenn immer numerische Werte gespeichert werden und führende Nullen nicht signifikant sind, ist das Speichern als numerischer Typ kompakter.
Martin Smith

Antworten:

14

Ihr Index ist anscheinend in Ordnung und gut (dh deckt ab) für die Abfrage und sollte verwendet werden. Das eigentliche Problem ist die Abfrage selbst und insbesondere diese Bedingung, die eine implizite Konvertierung verbirgt:

WHERE [serialNumber] = 137802

Gemäß der Datentyp-Priorität von SQL Server wird beim Vergleich zweier Werte unterschiedlicher Datentypen der Wert mit dem Datentyp niedrigerer Priorität in den Datentyp höherer Priorität konvertiert. Ist leider inthöher in der Liste als varchar. Dies lässt die Hoffnung aufkommen, den Index zu verwenden, wenn die column ( serialNumber) -Werte in Ganzzahlen konvertiert werden. Die Spalte, die die 1. Position des Index darstellt, führt dazu, dass der Optimierer diesen Index nicht verwendet und nach einer Alternative (und damit nach dem Vorschlag) sucht.

Die Lösung besteht darin, keine impliziten oder expliziten Konvertierungen von Spalten in WHEREBedingung zu haben. Verwenden Sie einfach:

WHERE [serialNumber] = '137802'
ypercubeᵀᴹ
quelle
1
Vielen Dank! Kleines Versehen aufgrund der Verwendung nur numerischer Daten zum Testen, wenn das Feld serialNumber Alpha-Zeichen enthalten könnte. Da der Aufruf von .Net alle Werte umschließt, wäre dies in der Produktion wahrscheinlich nie zu sehen gewesen, aber der dumme Fehler meinerseits beim Test hat mir geholfen, etwas Neues über Indizes und explizite Konvertierungen zu lernen! Vielen Dank!
Hooligancat