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, D
eine Abfrage abdecken würde, wo A, B, C
oder A, B
oder ausgeführt A
wü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. :-)
quelle
SerialNumber
und die andere istsName
. 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).IDX_myIndex
nicht verwendet? Was ist der eigentliche Abfrageplan?WHERE [serialNumber] = 137802
während die Spalte ein Varchar ist. Ich wette, das ist der Grund für die Beschwerden.serialNumber
a überhaupt,varchar
wenn 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.Antworten:
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:
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
int
höher in der Liste alsvarchar
. 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
WHERE
Bedingung zu haben. Verwenden Sie einfach:quelle