Velikost tabulky a řádku v tabulkách optimalizovaných pro paměť
platí pro:SQL Server
Azure SQL Database
azure 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ů:
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:
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.
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ž 200
obsahuje 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 typem2 + 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 NULL
schopný (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 = 1NULL
odsazení pole = 1, protožeNULL
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á typnvarchar
.
<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.
Související obsah
- Ukázková databáze pro In-Memory OLTP