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.
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:
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
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?
Antworten:
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.
quelle
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.
quelle
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
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
Wenn ich nun meine Abfragen erneut mit Statistik-E / A ausführe:
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
quelle