Ich habe eine Tabelle CustPassMaster
mit 16 Spalten, von denen eine ist CustNum varchar(8)
, und ich habe einen Index erstellt IX_dbo_CustPassMaster_CustNum
. Wenn ich meine SELECT
Aussage mache:
SELECT * FROM dbo.CustPassMaster WHERE CustNum = '12345678'
Der Index wird vollständig ignoriert. Das verwirrt mich, da ich eine andere Tabelle CustDataMaster
mit viel mehr Spalten habe (55), von denen eine ist CustNum varchar(8)
. Ich habe einen Index für diese Spalte ( IX_dbo_CustDataMaster_CustNum
) in dieser Tabelle erstellt und verwende praktisch dieselbe Abfrage:
SELECT * FROM dbo.CustDataMaster WHERE CustNum = '12345678'
Und es verwendet den Index, den ich erstellt habe.
Gibt es dafür eine bestimmte Begründung? Warum sollte es den Index von verwenden CustDataMaster
, aber nicht den von CustPassMaster
? Liegt es an der geringen Spaltenanzahl?
Die erste Abfrage gibt 66 Zeilen zurück. Für die zweite Zeile wird 1 Zeile zurückgegeben.
Zusätzlicher Hinweis: CustPassMaster
4991 Datensätze und CustDataMaster
5376 Datensätze. Könnte dies der Grund dafür sein, den Index zu ignorieren? CustPassMaster
hat auch doppelte Datensätze, die die gleichen CustNum
Werte haben. Ist das ein weiterer Faktor?
Ich stütze diese Behauptung auf die tatsächlichen Ausführungsplanergebnisse beider Abfragen.
Hier ist die DDL für CustPassMaster
(die mit dem nicht verwendeten Index):
CREATE TABLE dbo.CustPassMaster(
[CustNum] [varchar](8) NOT NULL,
[Username] [char](15) NOT NULL,
[Password] [char](15) NOT NULL,
/* more columns here */
[VBTerminator] [varchar](1) NOT NULL
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_dbo_CustPassMaster_CustNum] ON dbo.CustPassMaster
(
[CustNum] ASC
) WITH (PAD_INDEX = OFF
, STATISTICS_NORECOMPUTE = OFF
, SORT_IN_TEMPDB = OFF
, DROP_EXISTING = OFF
, ONLINE = OFF
, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Und die DDL für CustDataMaster
(ich habe viele irrelevante Felder weggelassen):
CREATE TABLE dbo.CustDataMaster(
[CustNum] [varchar](8) NOT NULL,
/* more columns here */
[VBTerminator] [varchar](1) NOT NULL
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_dbo_CustDataMaster_CustNum] ON dbo.CustDataMaster
(
[CustNum] ASC
)WITH (PAD_INDEX = OFF
, STATISTICS_NORECOMPUTE = OFF
, SORT_IN_TEMPDB = OFF
, DROP_EXISTING = OFF
, ONLINE = OFF
, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Ich habe keinen Clustered-Index für eine dieser Tabellen, nur einen Nonclustered-Index.
Ignorieren Sie die Tatsache, dass die Datentypen nicht vollständig mit dem gespeicherten Datentyp übereinstimmen. Diese Felder sind eine Sicherung aus einer IBM AS / 400-DB2-Datenbank, und dies sind die kompatiblen Datentypen dafür. (Ich muss in der Lage sein, diese Sicherungsdatenbank mit denselben Abfragen abzufragen und dieselben Ergebnisse zu erzielen.)
Diese Daten werden nur für SELECT
Aussagen verwendet. Ich mache keine INSERT
/ UPDATE
/ DELETE
Aussagen auf sie, mit Ausnahme , wenn die Backup - Anwendung ist das Kopieren von Daten aus dem AS / 400.
quelle
Antworten:
Normalerweise werden Indizes von SQL Server verwendet, wenn die Verwendung des Index für zweckmäßiger erachtet wird als die direkte Verwendung der zugrunde liegenden Tabelle.
Es scheint wahrscheinlich, dass der kostenbasierte Optimierer denkt, dass es teurer wäre, den fraglichen Index tatsächlich zu verwenden. Sie können sehen, dass der Index verwendet wird, wenn
SELECT *
Sie dies nicht einfach tunSELECT T1Col1
.Wenn Sie
SELECT *
SQL Server anweisen, alle Spalten in der Tabelle zurückzugeben. Zurückgeben dieser Spalten SQL Server muss die Seiten für die Zeilen, die denWHERE
Anweisungskriterien entsprechen, aus der Tabelle selbst lesen (Clustered-Index oder Heap). SQL Server denkt wahrscheinlich, dass die Anzahl der Lesevorgänge, die erforderlich sind, um den Rest der Spalten aus der Tabelle abzurufen, auch dazu führen kann, dass die Tabelle direkt gescannt wird. Es wäre nützlich, die tatsächliche Abfrage und den von der Abfrage verwendeten tatsächlichen Ausführungsplan anzuzeigen.quelle
INCLUDE
Klausel des Index aufzunehmen.INCLUDE
Klausel alle von der Abfrage zurückgegebenen Spalten hinzufügen, wird SQL Server wahrscheinlich den Index verwenden. Was versuchen Sie zu optimieren? Es scheint mir, wenn Ihre Tabelle eine durchschnittliche Zeilengröße von 100 Bytes hat, dann sind 5000 Zeilen nur etwa 500 KB Daten und es kann durchaus sein, dass es sich nicht lohnt, Zeit dafür zu investieren.Table1
und 0,53 KB fürTable2
. Alle diese Daten werden von einem AS / 400-System (IBM System i) importiert und es befinden sich KEINE PKs auf irgendetwas. Ich habe heute alle Indizes manuell erstellt, nachdem die Leute erwähnt haben, dass die Anwendung zeitweise recht langsam ist.Damit Sie den Index verwenden können,
select *
muss SQL Server zunächst alle Zeilen aus dem Index lesen, die mit dem Wert übereinstimmen, den Sie in der where-Klausel angegeben haben. Auf dieser Grundlage werden die Clustered-Index-Werte für jede Zeile abgerufen, und anschließend muss jede einzelne von ihnen separat vom Clustered-Index gesucht werden (= Schlüsselsuche). Da Sie angegeben haben, dass die Werte nicht eindeutig sind, verwendet SQL Server Statistiken, um abzuschätzen, wie oft diese Schlüsselsuche durchgeführt werden muss.Höchstwahrscheinlich übersteigt der Kostenvoranschlag für das Scannen der nicht gruppierten Index- und Schlüsselsuche den Kostenvoranschlag für das Scannen des gruppierten Index, weshalb der Index ignoriert wird.
Sie können versuchen,
set statistics io on
einen Indexhinweis zu verwenden, um festzustellen, ob die E / A-Kosten bei Verwendung des Index tatsächlich geringer sind oder nicht. Wenn der Unterschied groß ist, können Sie Statistiken einsehen, wenn diese nicht mehr aktuell sind.Wenn in Ihrem SQL-Code tatsächlich Variablen und nicht die genauen Werte verwendet werden, kann dies auch durch Parameter-Sniffing verursacht werden (= der vorherige Wert, der zum Erstellen des Plans verwendet wurde, enthielt viele Zeilen in der Tabelle).
quelle
Das könnte der Grund sein. Die Optimierer sind kostenbasiert und entscheiden, welchen Pfad sie basierend auf den Kosten wählen, die jeder Ausführungspfad hat. Die 'größten' Kosten entstehen, wenn die Daten von der Festplatte in den Speicher übertragen werden. Wenn das Optimierungsprogramm berechnet, dass das Lesen des Index und der Daten länger dauert, wird möglicherweise der Index übersprungen. Je größer die Zeilen sind, desto mehr Plattenblöcke werden benötigt.
quelle