it-swarm-eu.dev

Rozdíl ve výkonu mezi klastrovaným a neklastrovaným indexem

Četl jsem Clustered a Non Clustered Indexes.

Clustered Index - Obsahuje datové stránky. To znamená, že ve sloupci Clustered Index Column budou k dispozici úplné informace o řádku.

Non Clustered Index - Obsahuje pouze informace o lokátoru řádků ve formě sloupcového indexu Clustered Index (pokud jsou k dispozici) nebo identifikátor souboru + číslo stránky + celkový počet řádků na stránce. To znamená, že vyhledávací stroj musí provést další krok k nalezení skutečných dat.

Query - Jak mohu zkontrolovat rozdíl ve výkonu pomocí praktického příkladu, protože víme, že tabulka může mít pouze jeden Clustered Index a poskytuje sorting na Clustered Index Column a Non Clustered Index neposkytují sorting a mohou podporovat 999 Non Clustered Indexes v SQL Server 2008 a 249 v SQL Server 2005.

22
Pankaj Garg

Velmi dobrá otázka, protože se jedná o tak důležitý koncept. To je ale velké téma a to, co vám ukážu, je zjednodušení, abyste pochopili základní pojmy.

Zaprvé, když uvidíte seskupený index think table . Na serveru SQL, pokud tabulka neobsahuje seskupený index, je to halda. Vytvoření seskupeného indexu v tabulce transformuje tabulku do struktury typu b-tree. Váš seskupený index IS tabulka není oddělený od tabulky)

Přemýšleli jste někdy, proč můžete mít pouze jeden seskupený index? Pokud bychom měli dva seskupené indexy, potřebovali bychom dvě kopie tabulky. Konec konců obsahuje data.

Pokusím se to vysvětlit pomocí jednoduchého příkladu.

POZNÁMKA: V tomto příkladu jsem vytvořil tabulku a naplnil ji více než 3 miliony náhodných položek. Poté spustil skutečné dotazy a vložil zde plány provádění.

To, co opravdu potřebujete pochopit, je O notace nebo provozní efektivita. Předpokládejme, že máte následující tabulku.

CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [varchar](100) NOT NULL,
[CustomerSurname] [varchar](100) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
[CustomerID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS  = ON
  , ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Tady máme základní tabulku s klastrovým klíčem na ID zákazníka (primární klíč je ve výchozím nastavení klastrovaný). Tabulka je tedy uspořádána/uspořádána na základě primárního klíče CustomerID. Střední úrovně budou obsahovat hodnoty CustomerID. Datové stránky budou obsahovat celý řádek, tedy řádek tabulky.

V poli CustomerName také vytvoříme index bez klastrů. Následující kód to udělá.

CREATE NONCLUSTERED INDEX [ix_Customer_CustomerName] ON [dbo].[Customer] 
 (
[CustomerName] ASC
 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF
  , DROP_EXISTING = OFF, ONLINE = OFF
  , ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

V tomto indexu byste tedy na uzlech na úrovni datových stránek/listů našli ukazatel na střední úrovně v seskupeném indexu. Index je uspořádán/uspořádán kolem pole CustomerName. Střední úroveň tedy obsahuje hodnoty CustomerName a úroveň listu bude obsahovat ukazatel (tyto hodnoty ukazatele jsou ve skutečnosti hodnoty primárního klíče nebo sloupec CustomerID).

Správně, pokud provedeme následující dotaz:

SELECT * FROM Customer WHERE CustomerID = 1 

SQL pravděpodobně přečte seskupený index pomocí operace vyhledávání. Operace vyhledávání je binární vyhledávání, které je mnohem účinnější než skenování, což je sekvenční vyhledávání. Takže v našem výše uvedeném příkladu je index čten a pomocí binárního vyhledávání může SQL eliminovat data, která neodpovídají hledaným kritériím. Viz přiložený snímek obrazovky pro plán dotazů.

enter image description here

Počet operací nebo O zápis pro operaci vyhledávání je tedy následující:

  1. Proveďte binární vyhledávání v seskupeném indexu porovnáním hledané hodnoty s hodnotami na střední úrovni.
  2. Vraťte hodnoty, které se shodují (pamatujte, protože seskupený index obsahuje všechna data v něm, může vrátit všechny sloupce z indexu, protože se jedná o data řádků)

Jedná se tedy o dvě operace. Pokud jsme však provedli následující dotaz:

SELECT * FROM Customer WHERE CustomerName ='John'

SQL nyní použije k provedení hledání index bez clusterů na CustomerName. Protože se však jedná o index bez klastrů, neobsahuje všechna data v řádku.

SQL tedy provede vyhledávání na středně pokročilých úrovních, aby našla záznamy, které se shodují, a poté provede vyhledávání pomocí vrácených hodnot, aby provedla další vyhledávání v seskupeném indexu (aka tabulka), aby načítala skutečná data. Zní to matoucí, že vím, ale čtu dál, a vše se vyjasní.

Protože náš index bez klastru obsahuje pouze pole CustomerName (hodnoty indexovaného pole uložené v mezilehlých uzlech) a ukazatel na data, která jsou CustomerID, index nemá žádný záznam CustomerSurname. Název zákazníka musí být vyvolán z seskupeného indexu nebo tabulky.

Při spuštění tohoto dotazu dostanu následující plán provedení:

enter image description here

Na snímku nahoře jsou dvě důležité věci

  1. SQL říká, že mám chybějící index (text zeleně). SQL navrhuje, abych vytvořil index na CustomerName, který zahrnuje CustomerID a CustomerSurname.
  2. Uvidíte také, že 99% času dotazu je věnováno vyhledávání klíče v indexu primárního klíče/seskupeném indexu.

Proč SQL navrhuje index na CustomerName znovu? Protože index obsahuje pouze CustomerID a SQL CustomerName SQL musí stále najít CustomerSurname z tabulky/seskupených indexů.

Pokud bychom vytvořili index a zahrnuli jsme do indexu sloupec CustomerSurname, SQL by bylo schopno uspokojit celý dotaz pouhým přečtením neklastrovaného indexu. To je důvod, proč SQL navrhuje, abych změnil svůj index bez klastrů.

Zde vidíte další operaci, kterou musí SQL udělat, aby získal sloupec CustomerSurname ze seskupeného klíče

Počet operací je tedy následující:

  1. Proveďte binární vyhledávání na indexu bez klastrů porovnáním hledané hodnoty s hodnotami na střední úrovni
  2. U uzlů, které se shodují, přečtěte uzel na úrovni listů, který bude obsahovat ukazatel pro data v seskupeném indexu (uzly na úrovni listů budou mimochodem obsahovat hodnoty primárních klíčů).
  3. Pro každou vrácenou hodnotu proveďte čtení v seskupeném indexu (v tabulce), abyste zde dostali hodnoty řádků, přečetli jsme jméno zákazníka.
  4. Vrátit odpovídající řádky

To jsou 4 operace k získání hodnot. Ve srovnání se čtením seskupeného indexu je třeba dvakrát tolik operací. Ukáže vám, že váš seskupený index je váš nejsilnější index, protože obsahuje všechna data.

Takže jen objasnit jeden poslední bod. Proč říkám, že ukazatel v neklastrovaném indexu je hodnota primárního klíče? Abychom demonstrovali, že uzly na úrovni listů neklastrovaného indexu obsahují hodnotu primárního klíče, změním svůj dotaz na:

SELECT CustomerID
FROM Customer
WHERE CustomerName='Jane'

V tomto dotazu SQL může číst CustomerID z indexu bez klastrů. Není třeba provádět vyhledávání v seskupeném indexu. To můžete vidět v plánu provádění, který vypadá takto.

enter image description here

Všimněte si rozdílu mezi tímto a předchozím dotazem. Neexistuje žádné vyhledávání. SQL může najít všechna data v indexu bez klastrů

Doufejme, že můžete začít chápat, že seskupený index je tabulka, a neslastované indexy NEBUDOU obsahovat všechna data. Indexování zrychlí výběr, protože lze provést binární vyhledávání, ale všechna data obsahují pouze seskupené indexy. Výsledkem hledání v neslastovaném indexu tak bude téměř vždy výsledné načítání hodnot z klastrovaného indexu. Tyto operace navíc způsobují, že neoklastované indexy jsou méně účinné než klastrovaný index.

Doufám, že to vyjasní věci. Pokud něco nedává smysl, napište komentář a pokusím se to objasnit. Je tu dost pozdě a můj mozek se cítí trochu plochý. Čas na červeného býka.

43
Namphibian

"To znamená, že vyhledávací stroj musí provést další krok, aby nalezl skutečná data."

Ne nutně - pokud index pokrývá daný dotaz, není nutné provádět žádné cesty na datové stránky. Se zahrnutými sloupci mohou být také přidány další sloupce do indexu bez klastrů, aby byl pokrytý beze změny velikosti klíče.

Takže konečná odpověď zní - záleží (na mnohem více informacích, než kolik můžete v jedné otázce skutečně pokrýt) - musíte pochopit všechny schopnosti indexů a plán provádění daného dotazu se může lišit od vašich očekávání.

Obecným pravidlem je, že tabulka má vždy seskupený index (a obvykle na identifikaci nebo sekvenčním GUID), ale pro výkon jsou přidávány neslastované indexy. Ale vždy existují výjimky - tabulky haldy mají místo, širší seskupené indexy mají místo. Zdánlivě nadbytečné indexy, které jsou užší, aby se vešly více řádků na stránku, mají své místo. atd. atd. atd.

A já bych si nedělal starosti s limity různých indexů povolených - to téměř určitě nebude hrát ve hře v mnoha příkladech reálného světa.

9
Cade Roux