Všiml jsem si, že jen velmi málo lidí rozumí tomu, jak fungují indexy na serveru SQL Server, zejména zahrnuté sloupce. Nicméně indexy jsou skvělým způsobem, jak optimalizovat dotazy. Zpočátku jsem také neměl představu o zahrnutých sloupcích, ale mé experimenty ukázaly, že jsou velmi užitečné.
Předpokládejme, že máme následující tabulku a dotaz:
CREATE TABLE Person ( PersonID int, FirstName varchar(100), LastName varchar(100), Age int, … … ) SELECT FirstName, LastName, Age FROM Person WHERE FirstName = 'John' and LastName = 'Smith'
Je jasné, že PersonID je primární klíč. Předpokládejme, že máme index podle jména a příjmení, nazvěme ho IX_Person_FirstNamePříjmení. Plán provádění takového dotazu bude vypadat následovně:
- Vyhledání všech řádků se zadaným jménem a příjmením pomocí indexového stromu IX_Person_FirstNameLastName
- Zjištění skutečného umístění řádku na disku na listech indexu, přechod na skutečné umístění a přečtení stáří.
Nyní uvažujme, že tento dotaz se provádí poměrně často. Pokaždé musíme provést 2 kroky. Dá se to optimalizovat? V případě MS SQL Serveru to není problém – hodnoty můžete zahrnout přímo do indexu pomocí volby INCLUDE.
CREATE INDEX IX_PERSON ON Person ( FirstName, LastName ) INCLUDE(Age)
Nyní se toto pole nepoužívá během indexování, ale je zahrnuto do indexu. S jakými potížemi se v tomto ohledu můžeme potýkat? Když indexujeme tabulku podle určitého pole, databázový server musí podle tohoto pole vytvořit strom indexu. To znamená, že při změně hodnoty musíme změnit strom indexu. Při intenzivních úpravách hodnot se to pro server stává problematickým a těžkým úkolem. Když je aktualizace příliš rozsáhlá, je někdy snazší index vypustit. Index výrazně optimalizuje vyhledávání, ale negativně ovlivňuje operace vkládání, mazání a aktualizace.
Pokud je pole jednoduše zahrnuto do indexu, není použito při vytváření stromu indexu a neovlivňuje jej, ale hodnotu lze snadno zjistit na listu tohoto stromu. Když probíhá vyhledávání podle příjmení a křestních jmen, server vyhledává všechna jména a příjmení ze stromu, a když se dostane na list (najde požadovanou hodnotu indexu), pak kromě ukazatele na fyzické umístění z hodnot řádku obsahuje také hodnoty polí zahrnuté v indexu. To znamená, že není třeba dělat druhý krok pro přepnutí na fyzické umístění řádku a číst ho odtud.
Vzhledem k tomu, že při úpravě údajů o věku nemusíte měnit strom, všechny tyto věci příliš neovlivňují operace úpravy dat. Nemusíme měnit index, stačí změnit hodnoty na listu stromu. Proto ani masivní změna pole Věk nebude mít velký dopad na výkon. Určitě to ovlivní, ale ne tolik.
Pokud vím, hodnoty seskupeného indexu jsou automaticky zahrnuty do úrovně listu, ale to je třeba zkontrolovat ve specifikaci.
Kdy je tedy použití zahrnutých polí přínosné? Když se často používají ve výsledcích dotazu, ale jednou za čas se mění. Příkladem je tabulka bankovních transakcí. Tato tabulka se může skládat z následujících polí:číslo účtu, typ transakce, datum, částka. Indexovat podle součtu nemá smysl, ale můžeme to zahrnout do indexu a výrazně to urychlí dotaz.
Abychom získali skutečný efekt z indexování, dotazy by neměly vybírat všechna pole, tj. měli bychom zapomenout na tabulku SELECT * FROM. Vždy přepočítejte jen ta pole, která skutečně potřebujete. A pokud se jejich hodnoty objeví v indexu, rychlost provádění může být poměrně vysoká.
Užitečný nástroj:
dbForge Index Manager – praktický doplněk SSMS pro analýzu stavu indexů SQL a řešení problémů s fragmentací indexů.