Biorąc pod uwagę następny przykład:
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
Jeśli pobiorę wszystkie rekordy uporządkowane według [nki]
(Indeks nieklastrowany):
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
Optymalizator wybiera indeks klastrowany, a następnie stosuje algorytm sortowania.
Ale jeśli wymuszę użycie indeksu nieklastrowego:
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
Następnie używa indeksu nieklastrowego z wyszukiwaniem klucza:
Oczywiście, jeśli indeks nieklastrowany zostanie przekształcony w indeks pokrywający:
CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
ON [dbo].[my_table] ([nki] ASC)
INCLUDE (id, foo, bar);
GO
Następnie używa tylko tego indeksu:
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
Pytanie
- Dlaczego program SQL Server używa indeksu klastrowego i algorytmu sortowania zamiast indeksu nieklastrowego, nawet jeśli w drugim przypadku czas wykonania jest o 38% krótszy?
Odpowiedzi:
Ponieważ SQL Server używa optymalizatora opartego na kosztach opartego na statystykach, a nie informacjach o środowisku wykonawczym.
Podczas procesu szacowania kosztów dla tego zapytania faktycznie ocenia plan wyszukiwania, ale szacuje, że zajmie to więcej wysiłku. (Zwróć uwagę na „Szacowany koszt poddrzewa”, gdy najedziesz kursorem myszy na SELECT w planie wykonania). To niekoniecznie złe założenie - na moim komputerze testowym plan wyszukiwania zajmuje 6X procesora sortowania / skanowania.
Spójrz na odpowiedź Roba Farleya, dlaczego SQL Server może kosztować plan wyszukiwania wyższy.
źródło
Jeśli porównasz liczbę odczytów wymaganą w 100 000 odnośników z tym, co wiąże się z wykonaniem sortowania, możesz szybko zorientować się, dlaczego Optymalizator zapytań stwierdza, że CIX + Sort byłby najlepszym wyborem.
Wykonywanie wyszukiwania kończy się szybciej, ponieważ czytane strony są w pamięci (nawet jeśli wyczyścisz pamięć podręczną, masz wiele wierszy na stronę, więc czytasz te same strony w kółko, ale z różną fragmentacją lub inna presja pamięci od innej aktywności, może nie być tak). Naprawdę nie wymagałoby to aż tyle, aby CIX + Sort działał szybciej, ale widzisz, ponieważ koszt czytania nie bierze pod uwagę względnej taniej wielokrotnego odwiedzania tych samych stron.
źródło
Postanowiłem trochę zagłębić się w to pytanie i znalazłem kilka interesujących dokumentów mówiących o tym, jak i kiedy używać, a może lepiej, a nie (wymuszać) stosowanie indeksu nieklastrowanego.
Jak sugerują komentarze Johna Eisbrenera , jednym z najczęściej cytowanych, nawet na innych blogach, jest ten interesujący artykuł Kimberly L. Tripp:
ale nie jest to jedyny, jeśli jesteś zainteresowany, możesz spojrzeć na te strony:
Jak widać, wszystkie poruszają się wokół koncepcji punktu krytycznego .
Cytat z artykułu KL Tripp
Gdy SQL Server używa indeksu nieklastrowego na stercie, w zasadzie pobiera listę wskaźników do stron tabeli podstawowej. Następnie używa tych wskaźników, aby pobrać wiersze za pomocą serii operacji o nazwie Wyszukiwanie identyfikatorów wierszy (RID). Oznacza to, że przynajmniej użyje tyle odczytów strony, ile zwróconych wierszy, i być może więcej. Proces jest nieco podobny z indeksem klastrowym jak tabela podstawowa, z tym samym rezultatem: więcej odczytów.
Ale kiedy nastąpi ten punkt krytyczny?
Oczywiście, jak większość rzeczy w tym życiu, zależy ...
Nie poważnie, występuje między 25% a 33% liczby stron w tabeli, w zależności od liczby wierszy na stronie. Ale jest więcej czynników, które należy wziąć pod uwagę:
Cytat z artykułu ITPRoToday
Teraz, jeśli ponownie wykonam moje zapytania za pomocą statystyk IO:
Drugie zapytanie wymaga więcej logicznych odczytów niż pierwsze.
Czy powinienem unikać indeksu nieklastrowanego?
Nie, indeks klastrowy może być przydatny, ale warto poświęcić trochę czasu i podjąć dodatkowy wysiłek, analizując, co próbujesz osiągnąć za jego pomocą.
Cytat z artykułu KL Tripp
źródło