Sdílet prostřednictvím


Velikost tabulky a řádku v tabulkách optimalizovaných pro paměť

platí pro:SQL ServerAzure SQL Databaseazure SQL Managed Instance

Před SQL Serverem 2016 (13.x) nemohla být velikost dat v řádku tabulky optimalizované pro paměť delší než 8 060 bajtů. Počínaje SQL Serverem 2016 (13.x) a v Azure SQL Database můžete ale vytvořit tabulku optimalizovanou pro paměť s několika velkými sloupci (například více varbinary(8000) sloupců) a LOB sloupci (tj. varbinary(max), varchar(max)a nvarchar(max)), a provádět operace s nimi pomocí nativně kompilovaných modulů Transact-SQL (T-SQL) a typů tabulek.

Sloupce, které se nevejdou do limitu velikosti řádku 8 060 bajtů, se umístí mimo řádek v samostatné interní tabulce. Každý sloupec mimo řádek má odpovídající interní tabulku, která má zase jeden neclusterovaný index. Podrobnosti o těchto interních tabulkách používaných pro sloupce nezahrnuté do řádku najdete viz sys.memory_optimized_tables_internal_attributes.

Existují určité scénáře, kdy je užitečné vypočítat velikost řádku a tabulky:

  • Kolik paměti tabulka používá.

    • Množství paměti používané tabulkou nelze vypočítat přesně. Množství využité paměti ovlivňuje mnoho faktorů. Faktory, jako přidělování paměti založené na stránkách, lokalita, ukládání do mezipaměti a odsazení. Existují také více verzí řádků, které mají přidružené aktivní transakce nebo které čekají na odpadkový sběr.

    • Minimální velikost potřebná pro data a indexy v tabulce je uvedena výpočtem pro <table size>, který je popsán dále v tomto článku.

    • Výpočet využití paměti je nejlepší aproximace a doporučujeme zahrnout plánování kapacity do plánů nasazení.

  • Velikost dat řádku a odpovídá omezení velikosti řádku 8 060 bajtů? Pokud chcete na tyto otázky odpovědět, použijte výpočty pro <row body size>, které jsou popsány dále v tomto článku.

Tabulka optimalizovaná pro paměť se skládá z kolekce řádků a indexů, které obsahují ukazatele na řádky. Následující obrázek znázorňuje tabulku s indexy a řádky, které zase obsahují záhlaví a těla řádků:

diagram tabulky optimalizované pro paměť

Velikost výpočetní tabulky

Velikost tabulky v paměti v bajtech se vypočítá takto:

<table size> = <size of index 1> + ... + <size of index n> + (<row size> * <row count>)

Velikost indexu hash je pevně stanovena při vytváření tabulky a závisí na skutečném počtu kbelíků. bucket_count zadané definicí indexu se zaokrouhlí nahoru na nejbližší mocninu 2, aby bylo možné získat skutečný počet kbelíků. Pokud je například zadaný bucket_count 100000, skutečný počet kbelíků indexu 131072.

<hash index size> = 8 * <actual bucket count>

Velikost neclusterovaného indexu je v pořadí <row count> * <index key size>.

Velikost řádku se vypočítá přidáním záhlaví a textu:

<row size> = <row header size> + <actual row body size>
<row header size> = 24 + 8 * <number of indexes>

Vypočítat velikost těla řádku

Řádky v tabulce optimalizované pro paměť mají následující komponenty:

  • Záhlaví řádku obsahuje časové razítko potřebné k implementaci správy verzí řádků. Záhlaví řádku obsahuje také ukazatel indexu pro implementaci řetězení řádků v kontejnerech hash (popsáno dříve).

  • Tělo řádku obsahuje skutečná data sloupce a také některé pomocné informace, jako je pole nul pro nulovatelné sloupce a pole posunu pro datové typy s proměnnou délkou.

Následující obrázek znázorňuje strukturu řádků tabulky, která má dva indexy:

Diagram struktury řádků pro tabulku se dvěma indexy

Počáteční a koncové časové razítko označuje období, ve kterém je konkrétní verze řádku platná. Transakce, které začínají v tomto intervalu, mohou zobrazit tuto verzi řádku. Další informace naleznete v tématu Transakce a Memory-Optimized tabulky.

Ukazatele indexu odkazují na další řádek v řetězci, který patří do kontejneru hash. Následující obrázek znázorňuje strukturu tabulky se dvěma sloupci (jméno, město) a se dvěma indexy, jedním na sloupci jméno a jedním na sloupci město.

diagram struktury tabulky se dvěma sloupci a indexy.

Na tomto obrázku jsou názvy John a Jane hashovány do prvního kontejneru. Susan se zatřiďuje do druhého kontejneru. Města Beijing a Bogota se zatřiďují do prvního kontejneru. Paris a Prague se zatřiďují do druhého kontejneru.

Řetězy indexu hash pro název jsou tedy následující:

  • První kbelík: (John, Beijing); (John, Paris); (Jane, Prague)
  • Druhý kbelík: (Susan, Bogota)

Řetězce indexu ve městě jsou následující:

  • První kbelík: (John, Beijing), (Susan, Bogota)
  • Druhý kbelík: (John, Paris), (Jane, Prague)

Koncové časové razítko ∞ (nekonečno) označuje, že se jedná o aktuálně platnou verzi řádku. Řádek nebyl aktualizován nebo odstraněn, protože tato verze řádku byla napsána.

Pro dobu větší než 200obsahuje tabulka následující řádky:

Jméno Město
John Peking
Jana Praha

Však jakákoliv aktivní transakce s počátečním časem 100, viz následující verzi tabulky:

Jméno Město
John Paříž
Jana Praha
Zuzana Bogota

Výpočet <row body size> je popsán v následující tabulce.

Pro velikost textu řádku existují dva různé výpočty: vypočítaná velikost a skutečná velikost:

  • Vypočítaná velikost, označená jako vypočítaná velikost těla řádku, slouží k určení, jestli je překročeno omezení velikosti řádku 8 060 bajtů.

  • Skutečná velikost, označená jako skutečná velikost těla řádku, je skutečná velikost úložiště těla řádku v paměti a v souborech kontrolních bodů.

Jak vypočítané velikosti těla řádku, tak i skutečné velikosti těla řádku se vypočítávají podobně. Jediným rozdílem je výpočet velikosti (n)varchar(i) a varbinary(i) sloupců, jak se odráží v dolní části následující tabulky. Vypočítaná velikost těla řádku používá deklarovanou velikost i jako velikost sloupce, zatímco skutečná velikost textu řádku používá skutečnou velikost dat.

Následující tabulka popisuje výpočet velikosti těla řádku, který je uveden jako <actual row body size> = SUM(<size of shallow types>) + 2 + 2 * <number of deep type columns>.

Oddíl Velikost Komentáře
Mělký typ sloupce SUM(<size of shallow types>). Velikost v bajtech jednotlivých typů je následující:

bit: 1
tinyint: 1
smallint: 2
: 4
skutečné: 4
smalldatetime: 4
smallmoney: 4
bigint: 8
datum a čas: 8
datetime2: 8
plovoucí: 8
peněz: 8
číselné (přesnost <= 18): 8
čas: 8
číselné(přesnost > 18): 16
jedinečnýidentifikátor: 16
mělké odsazení sloupců Možné hodnoty:

1, pokud jsou sloupce hlubokého typu a celková velikost dat mělkých sloupců je liché číslo.

0 jinak
Hluboké typy jsou (var)binary a (n)(var)char.
pole posunu pro sloupce s hlubokým typem Možné hodnoty:

0, pokud neexistují žádné sloupce s hlubokým typem

2 + 2 * <number of deep type columns> jinak
Hluboké typy jsou typy (var)binary a (n)(var)char.
pole s hodnotou Null <number of nullable columns> / 8 zaokrouhleno nahoru na celé bajty. Pole má 1 bit na sloupec s nulovou hodnotou. Zaokrouhlí se nahoru na celé bajty.
Vyplňování pole nulovými hodnotami Možné hodnoty:

1, pokud jsou přítomny sloupce hlubokého typu a velikost pole NULL je lichý počet bajtů.
0 jinak
Hluboké typy jsou typy (var)binary a (n)(var)char.
odsazení Pokud neexistují žádné sloupce s hlubokým typem: 0

Pokud existují sloupce s hlubokým typem dat, přidá se vyrovnání o velikosti 0 až 7 bajtů na základě největšího zarovnání požadovaného mělkým sloupcem. Každý mělký sloupec vyžaduje zarovnání stejné velikosti, jak bylo uvedeno dříve, s tím rozdílem, že sloupce GUID potřebují zarovnání 1 bajtu (ne 16) a číselné sloupce vždy potřebují zarovnání 8 bajtů (nikdy 16). Používá se největší požadavek zarovnání mezi všemi mělkými sloupci. 0 až 7 bajtů odsazení se přidá takovým způsobem, že celková velikost (bez sloupců hloubkového typu) je násobkem požadovaného zarovnání.
Hluboké typy jsou (var)binary a (n)(var)char.
sloupce hlubokého typu s pevně danou délkou SUM(<size of fixed length deep type columns>)

Velikost každého sloupce je následující:

i pro char(i) a binary(i).
2 * i pro nchar(i)
Sloupce hlubokého typu s pevnou délkou jsou sloupce typu char(i), nchar(i)nebo binary(i).
sloupce hloubkového typu s proměnlivou délkou vypočítaná velikost SUM(<computed size of variable length deep type columns>)

Vypočítaná velikost každého sloupce je následující:

i pro varchar(i) a varbinary(i)

2 * i pro nvarchar(i)
Tento řádek se vztahuje pouze na vypočítanou velikost těla řádku.

Sloupce hloubkového typu s proměnlivou délkou jsou sloupce typu varchar(i), nvarchar(i)nebo varbinary(i). Vypočítaná velikost je určena maximální délkou (i) sloupce.
sloupce hloubkového typu s proměnnou délkou skutečné velikosti SUM(<actual size of variable length deep type columns>)

Skutečná velikost každého sloupce je následující:

n, kde n je počet znaků uložených ve sloupci, pro varchar(i).

2 * n, kde n je počet znaků uložených ve sloupci, pro nvarchar(i).

n, kde n je počet bajtů uložených ve sloupci, pro varbinary(i).
Tento řádek se vztahuje pouze na velikost skutečného těla řádku .

Skutečná velikost je určena daty, která jsou uložena v řádcích a sloupcích.

Příklad: Výpočet velikosti tabulky a řádku

U hašovacích indexů je skutečný počet bucketů zaokrouhlen nahoru na nejbližší mocninu dvou. Pokud je například zadaný bucket_count 100 000, skutečný počet segmentů indexu je 131072.

Zvažte tabulku Orders s následující definicí:

CREATE TABLE dbo.Orders (
    OrderID INT NOT NULL PRIMARY KEY NONCLUSTERED,
    CustomerID INT NOT NULL INDEX IX_CustomerID HASH WITH (BUCKET_COUNT = 10000),
    OrderDate DATETIME NOT NULL,
    OrderDescription NVARCHAR(1000)
)
WITH (MEMORY_OPTIMIZED = ON);
GO

Tato tabulka obsahuje jeden index hash a neclusterovaný index (primární klíč). Má také tři sloupce s pevnou délkou a jeden sloupec s proměnlivou délkou, přičemž jeden ze sloupců je NULLschopný (OrderDescription). Předpokládejme, že tabulka Orders obsahuje 8 379 řádků a průměrná délka hodnot ve sloupci OrderDescription je 78 znaků.

Pokud chcete určit velikost tabulky, nejprve určete velikost indexů. bucket_count pro oba indexy je zadán jako 1 0000. Zaokrouhluje se na nejbližší mocninu čísla 2: 16384. Celková velikost indexů pro tabulku Orders je tedy následující:

8 * 16384 = 131072 bytes

Co zbývá, je velikost dat tabulky, což je:

<row size> * <row count> = <row size> * 8379

(Ukázková tabulka obsahuje 8 379 řádků.) Teď máme:

<row size> = <row header size> + <actual row body size>
<row header size> = 24 + 8 * <number of indices> = 24 + 8 * 1 = 32 bytes

V dalším kroku vypočítáme <actual row body size>:

  • Sloupce s mělkým typem

    SUM(<size of shallow types>) = 4 <int> + 4 <int> + 8 <datetime> = 16
    
  • Odsazení v mělkém sloupci je 0, protože celková velikost sloupce je sudá.

  • Posun pole pro sloupce s hlubokým typem:

    2 + 2 * <number of deep type columns> = 2 + 2 * 1 = 4
    
  • NULL matice = 1

  • NULL odsazení pole = 1, protože NULL má lichou velikost a je přítomen hloubkový typ sloupce.

  • Polstrování

    • 8 je největší požadavek na zarovnání.
    • Velikost je zatím 16 + 0 + 4 + 1 + 1 = 22
    • Nejbližší násobek z 8 je 24
    • Celkové odsazení je 24 – 22 = 2 bajty
  • Neexistují žádné sloupce s hlubokým typem s pevnou délkou (počet sloupců s hlubokým typem s pevnou délkou: 0).

  • Skutečná velikost sloupce hlubokého typu je 2 * 78 = 156. Sloupec s jedním hlubokým typem OrderDescription má typ nvarchar.

<actual row body size> = 24 + 156 = 180 bytes

Dokončení výpočtu:

<row size> = 32 + 180 = 212 bytes
<table size> = 8 * 16384 + 212 * 8379 = 131072 + 1776348 = 1907420

Celková velikost tabulky v paměti je tedy přibližně 2 megabajty. To nezohledňuje potenciální režijní náklady způsobené přidělením paměti a ani žádné verzování řádků, které je vyžadováno pro transakce přistupující k této tabulce.

Skutečnou paměť přidělenou pro tuto tabulku a její indexy lze získat pomocí následujícího dotazu:

SELECT * FROM sys.dm_db_xtp_table_memory_stats
WHERE object_id = object_id('dbo.Orders');

Omezení nesouřadných sloupců

Určitá omezení a upozornění na použití sloupců mimo řádky v tabulce optimalizované pro paměť jsou uvedeny takto:

  • Pokud má tabulka optimalizovaná pro paměť index typu columnstore, musí se všechny sloupce vejít do řádku.
  • Všechny sloupce klíče indexu musí být uložené v řádku. Pokud se sloupec s klíčem indexu nevejde do řádku, přidání indexu se nezdaří.
  • Upozornění na změnu tabulky optimalizované pro paměť se sloupci mimo řádky.
  • U BLOBů se omezení velikosti zrcadlí na tabulkách využívajících úložiště na disku (omezení 2 GB pro hodnoty BLOB).
  • Pro optimální výkon doporučujeme, aby se většina sloupců vešla do 8 060 bajtů.
  • Data mimo řádky můžou způsobit nadměrné využití paměti nebo disku.