Warum sollte der Optimierer Clustered Index + Sort anstelle von Non-Clustered Index wählen?

11

Angesichts des nächsten Beispiels:

IF OBJECT_ID('dbo.my_table') IS NOT NULL
    DROP TABLE [dbo].[my_table];
GO

CREATE TABLE [dbo].[my_table]
(
    [id]    int IDENTITY (1,1)  NOT NULL PRIMARY KEY,
    [foo]   int                 NULL,
    [bar]   int                 NULL,
    [nki]   int                 NOT NULL
);
GO

/* Insert some random data */
INSERT INTO [dbo].[my_table] (foo, bar, nki)
SELECT TOP (100000)
    ABS(CHECKSUM(NewId())) % 14,
    ABS(CHECKSUM(NewId())) % 20,
    n = CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id]))
FROM 
    sys.all_objects AS s1 
CROSS JOIN 
    sys.all_objects AS s2
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
    ON [dbo].[my_table] ([nki] ASC);
GO

Wenn ich alle Datensätze abrufe, die nach [nki](Nicht-Clustered-Index) sortiert sind :

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 266 ms, elapsed time = 493 ms

Optimierer wählt den Clustered-Index aus und wendet dann einen Sortieralgorithmus an.

Geben Sie hier die Bildbeschreibung ein

Execution plan

Aber wenn ich es zwinge, den nicht gruppierten Index zu verwenden:

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 311 ms, elapsed time = 188 ms

Anschließend wird ein nicht gruppierter Index mit einer Schlüsselsuche verwendet:

Geben Sie hier die Bildbeschreibung ein

Execution plan

Wenn der nicht gruppierte Index in einen abdeckenden Index umgewandelt wird:

CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
    ON [dbo].[my_table] ([nki] ASC)
    INCLUDE (id, foo, bar);
GO

Dann wird nur dieser Index verwendet:

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 32 ms, elapsed time = 106 ms

Geben Sie hier die Bildbeschreibung ein

Execution plan


Frage

  • Warum verwendet SQL Server den Clustered-Index plus einen Sortieralgorithmus anstelle eines Nicht-Clustered-Index, auch wenn die Ausführungszeit im letzteren Fall 38% schneller ist?
McNets
quelle
1
Wollten Sie ORDER BY in Ihrer Forced-Index-Abfrage weglassen?
Forrest

Antworten:

9

Warum verwendet SQL Server den Clustered-Index plus einen Sortieralgorithmus anstelle eines Nicht-Clustered-Index, auch wenn die Ausführungszeit im letzteren Fall 38% schneller ist?

Da SQL Server ein kostenbasiertes Optimierungsprogramm verwendet, das auf Statistiken und nicht auf Laufzeitinformationen basiert.

Während des Kostenschätzungsprozesses für diese Abfrage wird der Suchplan zwar ausgewertet, es wird jedoch geschätzt, dass mehr Aufwand erforderlich ist. (Beachten Sie die "Geschätzten Teilbaumkosten", wenn Sie im Ausführungsplan mit der Maus über SELECT fahren.) Das ist auch nicht unbedingt eine schlechte Annahme - auf meinem Testcomputer benötigt der Suchplan das 6-fache der CPU der Sortierung / des Scans.

Schauen Sie sich Rob Farleys Antwort an, warum SQL Server den Suchplan möglicherweise höher kostet.

Wald
quelle
9

Wenn Sie die Anzahl der in 100.000 Suchvorgängen erforderlichen Lesevorgänge mit den für eine Sortierung erforderlichen Lesevorgängen vergleichen, erhalten Sie möglicherweise schnell eine Vorstellung davon, warum das Abfrageoptimierungsprogramm feststellt, dass CIX + Sort die beste Wahl ist.

Die Lookup-Ausführung ist schneller, da sich die gelesenen Seiten im Speicher befinden (selbst wenn Sie den Cache leeren, haben Sie viele Zeilen pro Seite, sodass Sie immer wieder dieselben Seiten lesen, jedoch mit unterschiedlicher Fragmentierung oder anderer Speicherdruck als bei anderen Aktivitäten, dies ist möglicherweise nicht der Fall). Es würde wirklich nicht viel kosten, CIX + Sort schneller zu machen, aber Sie sehen, dass die Kosten für einen Lesevorgang nicht die relative Billigkeit berücksichtigen, dieselben Seiten wiederholt aufzurufen.

Rob Farley
quelle
4

Ich habe mich entschlossen, mich ein wenig mit dieser Frage zu befassen, und ich habe einige interessante Dokumente herausgefunden, die darüber sprechen, wie und wann oder vielleicht besser, die Verwendung eines nicht gruppierten Index nicht erzwingen.

Wie aus den Kommentaren von John Eisbrener hervorgeht , ist dieser interessante Artikel von Kimberly L. Tripp einer der am häufigsten zitierten , selbst in anderen Blogs:

Aber es ist nicht die einzige. Wenn Sie interessiert sind, können Sie sich diese Seiten ansehen:

Wie Sie sehen können, bewegen sich alle um das Konzept des Wendepunkts .

Zitiert aus dem Artikel von KL Tripp

Was ist der Wendepunkt?

Es ist der Punkt, an dem die Anzahl der zurückgegebenen Zeilen " nicht mehr selektiv genug " ist. SQL Server verwendet NICHT den nicht gruppierten Index, um die entsprechenden Datenzeilen nachzuschlagen, und führt stattdessen einen Tabellenscan durch.

Wenn SQL Server einen nicht gruppierten Index für einen Heap verwendet, wird im Grunde eine Liste von Zeigern auf die Seiten der Basistabelle abgerufen. Anschließend werden diese Zeiger verwendet, um die Zeilen mit einer Reihe von Operationen abzurufen, die als Row ID Lookups (RID) bezeichnet werden. Dies bedeutet, dass mindestens so viele Seitenlesevorgänge verwendet werden wie die Anzahl der zurückgegebenen Zeilen und möglicherweise noch mehr. Der Prozess ist mit einem Clustered-Index wie der Basistabelle etwas ähnlich, mit dem gleichen Ergebnis: mehr Lesevorgänge.

Aber wann tritt dieser Wendepunkt auf?

Natürlich, wie die meisten Dinge in diesem Leben, kommt es darauf an ...

Nein im Ernst, es tritt zwischen 25% und 33% der Anzahl der Seiten in der Tabelle auf, abhängig von der Anzahl der Zeilen pro Seite. Es gibt jedoch noch weitere Faktoren, die Sie berücksichtigen sollten:

Zitiert aus dem ITPRoToday-Artikel

Andere Faktoren, die den Wendepunkt beeinflussen Obwohl die Kosten für RID-Suchvorgänge der wichtigste Faktor sind, der den Wendepunkt beeinflusst, gibt es eine Reihe anderer Faktoren:

  • Physische E / A sind beim Scannen eines Clustered-Index wesentlich effizienter. Clustered-Indexdaten werden nacheinander in Indexreihenfolge auf der Festplatte abgelegt. Folglich gibt es sehr wenig seitlichen Kopfweg auf der Platte, was die E / A-Leistung verbessert.
  • Wenn das Datenbankmodul einen Clustered-Index scannt, weiß es, dass es sehr wahrscheinlich ist, dass die nächsten Seiten auf der Festplattenspur noch die benötigten Daten enthalten. Es beginnt also mit dem Lesen in 64-KB-Blöcken anstelle der normalen 8-KB-Seiten. Dies führt auch zu einer schnelleren E / A.

Wenn ich nun meine Abfragen erneut mit Statistik-E / A ausführe:

SET STATISTICS IO ON;
SELECT id, foo, bar, nki FROM my_table WHERE nki < 20000 ORDER BY nki ;
SET STATISTICS IO OFF;

Logical reads: 312

SET STATISTICS IO ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS IO OFF;

Logical reads: 41293

Die zweite Abfrage erfordert mehr logische Lesevorgänge als die erste.

Sollte ich nicht gruppierten Index vermeiden?

Nein, ein Clustered-Index kann nützlich sein, aber es lohnt sich, sich Zeit zu nehmen und zusätzliche Anstrengungen zu unternehmen, um zu analysieren, was Sie damit erreichen möchten.

Zitiert aus dem Artikel von KL Tripp

Also, was solltest du tun? Es hängt davon ab, ob. Wenn Sie Ihre Daten gut kennen und einige umfangreiche Tests durchführen, sollten Sie einen Hinweis verwenden (es gibt einige clevere Dinge, die Sie programmgesteuert in sps ausführen können. Ich werde versuchen, diesem bald einen Beitrag zu widmen). Eine viel bessere Wahl (wenn überhaupt möglich) ist es jedoch, eine Abdeckung in Betracht zu ziehen (das ist wirklich mein Hauptpunkt :). In meinen Abfragen ist das Abdecken unrealistisch, weil meine Abfragen alle Spalten (das böse SELECT *) wollen. Wenn Ihre Abfragen jedoch enger sind UND eine hohe Priorität haben, ist es besser, einen Abdeckungsindex (in vielen Fällen) als einen Hinweis zu verwenden, weil Ein Index, der eine Abfrage abdeckt, gibt niemals Tipps.

Das ist die Antwort auf das Rätsel, aber es gibt definitiv noch viel mehr zu tun. Der Wendepunkt kann eine sehr gute Sache sein - und er funktioniert normalerweise gut. Wenn Sie jedoch feststellen, dass Sie einen Index erzwingen und eine bessere Leistung erzielen können, sollten Sie einige Nachforschungen anstellen und prüfen, ob dies der Fall ist. Überlegen Sie dann, wie wahrscheinlich es ist, dass ein Hinweis hilft, und jetzt wissen Sie, wo Sie sich konzentrieren können.

McNets
quelle