Sdílet prostřednictvím


Indexy v pamatově optimalizovaných tabulkách

platí pro: SQL Server Azure SQL DatabaseAzure SQL Managed Instance

Všechny tabulky optimalizované pro paměť musí mít alespoň jeden index, protože se jedná o indexy, které spojují řádky. V tabulce optimalizované pro paměť je každý index také optimalizován pro paměť. Index v tabulce optimalizované pro paměť se liší od tradičního indexu v tabulce založené na disku několika způsoby:

  • Řádky dat nejsou uloženy na stránkách, takže neexistuje žádná kolekce stránek nebo rozsahů, žádné oddíly ani alokační jednotky, na které se dají odkazovat, aby se na všechny stránky tabulky dostaly. Existuje koncept indexových stránek pro jeden z dostupných typů indexů, ale ukládají se odlišně než indexy pro diskové tabulky. Nenačítají tradiční typ fragmentace na stránce, a proto nemají žádný fillfactor.
  • Změny indexů v tabulkách optimalizovaných pro paměť během manipulace s daty se nikdy nezapisují na disk. Do transakčního protokolu se zapisují pouze řádky dat a změny dat.
  • Indexy optimalizované pro paměť se znovu sestaví, když se databáze vrátí do režimu online.

Všechny indexy v tabulkách optimalizovaných pro paměť se vytvářejí na základě definic indexů během obnovení databáze.

Index musí být jeden z následujících:

  • Hašovací index
  • Neclusterovaný index optimalizovaný pro paměť (což znamená výchozí interní strukturu stromu B)

Hash indexy jsou diskutovány podrobněji v Hash indexech pro pamětí optimalizované tabulky.
Neclusterované indexy jsou podrobněji popsány v neclusterovaný index pro paměťově optimalizované tabulky.
Indexy columnstore jsou popsány v jiném článku.

Syntaxe indexů optimalizovaných pro paměť

Každý příkaz CREATE TABLE pro tabulku optimalizovanou pro paměť musí obsahovat index, a to buď explicitně prostřednictvím indexu, nebo implicitně prostřednictvím omezení PRIMARY KEY nebo UNIQUE.

Pokud má být deklarována výchozí hodnota DURABILITY = SCHEMA_AND_DATA, paměťově optimalizovaná tabulka musí mít primární klíč. Klauzule PRIMARY KEY NONCLUSTERED v následujícím příkazu CREATE TABLE splňuje dva požadavky:

  • Poskytuje index, který splňuje minimální požadavek jednoho indexu v příkazu CREATE TABLE.

  • Poskytuje primární klíč, který je nutný pro klauzuli SCHEMA_AND_DATA.

    CREATE TABLE SupportEvent  
    (  
        SupportEventId   int NOT NULL  
            PRIMARY KEY NONCLUSTERED,  
        ...  
    )  
        WITH (  
            MEMORY_OPTIMIZED = ON,  
            DURABILITY = SCHEMA_AND_DATA);  
    

Poznámka:

SQL Server 2014 (12.x) a SQL Server 2016 (13.x) mají limit 8 indexů na tabulku nebo typ tabulky optimalizované pro paměť. Počínaje SQL Serverem 2017 (14.x) a ve službě Azure SQL Database už neexistuje omezení počtu indexů specifických pro tabulky a typy tabulek optimalizovaných pro paměť.

Ukázka kódu pro syntaxi

Tato pododdíl obsahuje blok kódu Transact-SQL, který ukazuje syntaxi pro vytvoření různých indexů v tabulce optimalizované pro paměť. Kód ukazuje následující:

  1. Vytvořte tabulku optimalizovanou pro paměť.

  2. Pomocí příkazů ALTER TABLE přidejte dva indexy.

  3. VLOŽTE několik řádků dat.

    DROP TABLE IF EXISTS SupportEvent;  
    go  
    
    CREATE TABLE SupportEvent  
    (  
        SupportEventId   int               not null   identity(1,1)  
        PRIMARY KEY NONCLUSTERED,  
    
        StartDateTime        datetime2     not null,  
        CustomerName         nvarchar(16)  not null,  
        SupportEngineerName  nvarchar(16)      null,  
        Priority             int               null,  
        Description          nvarchar(64)      null  
    )  
        WITH (  
        MEMORY_OPTIMIZED = ON,  
        DURABILITY = SCHEMA_AND_DATA);  
    go  
    
        --------------------  
    
    ALTER TABLE SupportEvent  
        ADD CONSTRAINT constraintUnique_SDT_CN  
        UNIQUE NONCLUSTERED (StartDateTime DESC, CustomerName);  
    go  
    
    ALTER TABLE SupportEvent  
        ADD INDEX idx_hash_SupportEngineerName  
        HASH (SupportEngineerName) WITH (BUCKET_COUNT = 64);  -- Nonunique.  
    go  
    
        --------------------  
    
    INSERT INTO SupportEvent  
        (StartDateTime, CustomerName, SupportEngineerName, Priority, Description)  
        VALUES  
        ('2016-02-23 13:40:41:123', 'Abby', 'Zeke', 2, 'Display problem.'     ),  
        ('2016-02-24 13:40:41:323', 'Ben' , null  , 1, 'Cannot find help.'    ),  
        ('2016-02-25 13:40:41:523', 'Carl', 'Liz' , 2, 'Button is gray.'      ),  
        ('2016-02-26 13:40:41:723', 'Dave', 'Zeke', 2, 'Cannot unhide column.');  
    go 
    

Duplicitní hodnoty klíče indexu

Duplicitní hodnoty pro klíč indexu můžou snížit výkon tabulek optimalizovaných pro paměť. Systém zpracovává duplikáty při průchodu vstupními řetězci pro většinu operací čtení a zápisu na index. Pokud řetězec duplicitních položek překročí 100 položek, může být snížení výkonu měřitelné.

Duplicitní hash hodnoty

Tento problém je více viditelný v případě indexů hash. Indexy hash trpí více z následujících důvodů:

  • Nižší náklady na operaci pro indexy hash.
  • Interference velkých duplicitních řetězců s řetězem kolizí hash.

Pokud chcete omezit duplicitu v indexu, vyzkoušejte následující úpravy:

  • Použijte neclusterovaný index.
  • Přidejte další sloupce na konec indexového klíče, abyste snížili počet duplicit.
    • Můžete například přidat sloupce, které jsou také v primárním klíči.

Další informace o kolizích hodnot hash najdete v tématu Indexy hash pro tabulky Memory-Optimized.

Příklad vylepšení

Tady je příklad, jak se vyhnout neefektivitě výkonu indexu.

Vezměte v Customers úvahu tabulku, která má primární klíč na CustomerIda má index ve sloupci CustomerCategoryID. V dané kategorii bude obvykle mnoho zákazníků. Proto bude v daném klíči indexu k dispozici mnoho duplicitních hodnot pro CustomerCategoryID.

V tomto scénáři je osvědčeným postupem použít neclusterovaný index pro (CustomerCategoryID, CustomerId). Tento index lze použít pro dotazy, které používají predikát zahrnující CustomerCategoryID, ale klíč indexu neobsahuje duplikaci. Proto duplicitní hodnoty CustomerCategoryID nebo nadbytečný sloupec v indexu nevedou k neeficienci v údržbě indexu.

Následující dotaz ukazuje průměrný počet duplicitních hodnot klíče indexu pro index CustomerCategoryID v tabulce Sales.Customersv ukázkové databázi WideWorldImporters.

SELECT AVG(row_count) FROM
    (SELECT COUNT(*) AS row_count 
	    FROM Sales.Customers
	    GROUP BY CustomerCategoryID) a

Pokud chcete vyhodnotit průměrný počet duplicit indexového klíče pro vlastní tabulku a index, nahraďte Sales.Customers názvem tabulky a nahraďte CustomerCategoryID seznamem sloupců klíče indexu.

Porovnání, kdy použít každý typ indexu

Povaha konkrétních dotazů určuje, jaký typ indexu je nejlepší volbou.

Při implementaci tabulek optimalizovaných pro paměť v existující aplikaci je obecným doporučením začít s neclusterovanými indexy, protože jejich schopnosti se více podobají možnostem tradičních clusterovaných a neclusterovaných indexů v tabulkách založených na disku.

Doporučení pro použití neclusterovaného indexu

Neclusterovaný index je vhodnější než index hash, pokud:

  • Dotazy mají klauzuli ORDER BY na indexovaném sloupci.
  • Dotazy, ve kterých se testují pouze počáteční sloupce indexu s více sloupci
  • Dotazy testují indexovaný sloupec pomocí WHERE klauzule s:
    • Nerovnost: WHERE StatusCode != 'Done'
    • Skenování rozsahu hodnot: WHERE Quantity >= 100

Ve všech následujících příkazech SELECT je neclusterovaný index vhodnější než index hash:

SELECT CustomerName, Priority, Description 
FROM SupportEvent  
WHERE StartDateTime > DateAdd(day, -7, GetUtcDate());  

SELECT StartDateTime, CustomerName  
FROM SupportEvent  
ORDER BY StartDateTime DESC; -- ASC would cause a scan.

SELECT CustomerName  
FROM SupportEvent  
WHERE StartDateTime = '2016-02-26';  

Doporučení pro použití indexu hash

Indexy hash se primárně používají pro vyhledávání bodů a ne pro kontroly rozsahu.

Hashový index je vhodnější než neklastrovaný index, když dotazy používají rovnostní predikáty a klauzule WHERE se mapuje na všechny sloupce klíčů indexu, jak je znázorněno v následujícím příkladu.

SELECT CustomerName 
FROM SupportEvent  
WHERE SupportEngineerName = 'Liz';

Index s více sloupci

Index s více sloupci může být neclusterovaný index nebo index hash. Předpokládejme, že sloupce indexu jsou col1 a col2. Vzhledem k následujícímu SELECT příkazu by byl pro optimalizátor dotazů užitečný jenom neclusterovaný index:

SELECT col1, col3  
FROM MyTable_memop  
WHERE col1 = 'dn';  

Index hash potřebuje klauzuli WHERE k určení testu rovnosti pro každý z jeho sloupců v klíči. Jinak index hash není pro optimalizátor dotazů užitečný.

Žádný typ indexu není užitečný, pokud WHERE klauzule určuje pouze druhý sloupec v klíči indexu.

Souhrnná tabulka pro porovnání scénářů použití indexu

V následující tabulce jsou uvedeny všechny operace podporované různými typy indexů. Ano znamená, že index může efektivně obsluhovat požadavek a ne znamená, že index nemůže efektivně splnit požadavek.

Operation Optimalizováno pro paměť,
hodnota hash
Optimalizováno pro paměť,
neklastrovaný
Založené na disku
(bez clusteru)
Prohledávání indexu, načtení všech řádků tabulky Ano Ano Ano
Vyhledávání v indexu pro rovnostní predikáty (=). Ano
(Vyžaduje se úplný klíč.)
Ano Ano
Vyhledávání v indexu pro nerovnosti a predikáty rozsahu
(>, <, <=, >=, BETWEEN).
Ne
(Výsledkem je prohledávání indexu.)
Ano 1 Ano
Získejte řádky v pořadí řazení, které odpovídá definici indexu. Ne Ano Ano
Načtěte řádky v pořadí řazení, které odpovídá obrácené definici indexu. Ne Ne Ano

1 Pro neclusterovaný index optimalizovaný pro paměť není k provedení hledání indexu vyžadován úplný klíč.

Automatická správa indexů a statistik

Využijte řešení, jako je například Adaptivní index Defrag , k automatické správě defragmentace indexů a aktualizací statistik pro jednu nebo více databází. Tento postup automaticky zvolí, zda se má index znovu sestavit nebo změnit uspořádání podle úrovně fragmentace, mimo jiné parametry, a aktualizovat statistiky lineární prahovou hodnotou.

Viz také

Průvodce návrhem indexu SQL Serveru
Hashové indexy pro paměťově optimalizované tabulky
Neclusterované indexy pro pamětí optimalizované tabulky
Adaptivního Indexu Defragmentace