Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
platí pro:SQL Server
Azure SQL Database
azure SQL Managed Instance
Tabulky optimalizované pro paměť vyžadují, aby existoval dostatek paměti k uchování všech řádků a indexů. Vzhledem k tomu, že paměť je konečný prostředek, je důležité pochopit a spravovat využití paměti ve vašem systému. Témata v této části se týkají běžných scénářů použití a správy paměti.
Bez ohledu na to, jestli vytváříte novou tabulku optimalizovanou pro paměť nebo migrujete existující tabulku založenou na disku do tabulky optimalizované pro In-Memory paměti OLTP, je důležité mít rozumný odhad potřeb paměti každé tabulky, abyste mohli zřídit server s dostatečnou pamětí. Tato část popisuje, jak odhadnout velikost paměti, kterou potřebujete uchovávat data pro tabulku optimalizovanou pro paměť.
Pokud uvažujete o migraci z tabulek založených na disku na tabulky optimalizované pro paměť, než budete pokračovat v tomto tématu, přečtěte si téma Určení, jestli by se měla přenést tabulka nebo uložená procedura do In-Memory OLTP pokyny, které tabulky se mají nejlépe migrovat. Všechna témata v části Migrace na In-Memory OLTP poskytují pokyny k migraci z diskových do tabulek optimalizovaných pro paměť.
Základní pokyny pro odhad požadavků na paměť
Počínaje SQL Serverem 2016 (13.x) není nijak omezena velikost tabulek optimalizovaných pro paměť, i když se tabulky musí vejít do paměti. V SQL Serveru 2014 (12.x) je podporovaná velikost dat 256 GB pro tabulky SCHEMA_AND_DATA.
Velikost tabulky optimalizované pro paměť odpovídá velikosti dat a režijním nákladům na záhlaví řádků. Při migraci tabulky založené na disku na optimalizováno pro paměť bude velikost tabulky optimalizované pro paměť přibližně odpovídat velikosti clusterovaného indexu nebo haldy původní diskové tabulky.
Indexy v tabulkách optimalizovaných pro paměť mají tendenci být menší než neclusterované indexy v tabulkách založených na disku. Velikost neklastrovaných indexů je v řádu [primary key size] * [row count]
. Velikost hash indexů je [bucket count] * 8 bytes
.
Pokud je aktivní úloha, je potřeba další paměť, aby se zohlednila správa verzí řádků a různé operace. To, kolik paměti je v praxi potřeba, závisí na úloze, ale aby bylo doporučení bezpečné, je začít s dvojnásobnou očekávanou velikostí tabulek a indexů optimalizovaných pro paměť a sledovat, jaké jsou požadavky na paměť v praxi. Režie pro správu verzí řádků vždy závisí na vlastnostech úlohy – zejména dlouhotrvající transakce zvyšují režii. U většiny úloh používajících větší databáze (např. >100 GB) jsou režijní náklady omezené (25% nebo méně).
Podrobný výpočet požadavků na paměť
Příklad tabulky optimalizované pro paměť
Zvažte následující schéma tabulky optimalizované pro paměť:
CREATE TABLE t_hk
(
col1 int NOT NULL PRIMARY KEY NONCLUSTERED,
col2 int NOT NULL INDEX t1c2_index
HASH WITH (bucket_count = 5000000),
col3 int NOT NULL INDEX t1c3_index
HASH WITH (bucket_count = 5000000),
col4 int NOT NULL INDEX t1c4_index
HASH WITH (bucket_count = 5000000),
col5 int NOT NULL INDEX t1c5_index NONCLUSTERED,
col6 char (50) NOT NULL,
col7 char (50) NOT NULL,
col8 char (30) NOT NULL,
col9 char (50) NOT NULL
) WITH (memory_optimized = on) ;
GO
Pomocí tohoto schématu určíme minimální paměť potřebnou pro tuto tabulku optimalizovanou pro paměť.
Paměť pro tabulku
Řádek tabulky optimalizovaný pro paměť se skládá ze tří částí:
Časová razítka
Záhlaví řádku a časová razítka = 24 bajtů.ukazatele indexu
Pro každý hashový index v tabulce má každý řádek 8-bajtový ukazatel adresy na další řádek v indexu. Vzhledem k tomu, že existují čtyři indexy, každý řádek přidělí 32 bajtů pro ukazatele indexu (8 bajtový ukazatel pro každý index).data
Velikost datové části řádku je určena součtem velikosti typu pro každý sloupec dat. V naší tabulce máme pět 4bajtů celých čísel, tři 50 bajtové sloupce znaků a jeden 30 bajtový sloupec znaků. Datová část každého řádku je tedy 4 + 4 + 4 + 4 + 4 + 50 + 50 + 30 + 50 nebo 200 bajtů.
Následuje výpočet velikosti 5 000 000 (5 milionů) řádků v tabulce optimalizované pro paměť. Celková paměť používaná datovými řádky se odhaduje takto:
Paměť pro řádky tabulky
Z výše uvedených výpočtů je velikost každého řádku v tabulce optimalizované pro paměť 24 + 32 + 200 nebo 256 bajtů. Vzhledem k tomu, že máme 5 milionů řádků, bude tabulka spotřebovávat 5 000 000 × 256 bajtů nebo 1 280 000 000 bajtů – přibližně 1,28 GB.
Paměť pro indexy
Paměť pro každý hash index
Každý index hash je pole hash s 8 bajtovými ukazateli adres. Velikost pole je nejlépe určena počtem jedinečných hodnot indexu pro daný index – například počet jedinečných hodnot col2 je dobrým výchozím bodem pro velikost pole pro t1c2_index. Pole hash, které je příliš velké, ztrácí paměť. Hashovací pole, které je příliš malé, snižuje výkon, protože dojde k příliš mnoha kolizím kvůli hodnotám hashujícím do stejného indexu.
Hashovací indexy umožňují velmi rychlé vyhledávání podle rovnosti, například:
SELECT * FROM t_hk
WHERE Col2 = 3;
Neclusterované indexy jsou pro vyhledávání rozsahů rychlejší, například:
SELECT * FROM t_hk
WHERE Col2 >= 3;
Pokud migrujete tabulku založenou na disku, můžete pomocí následujícího příkazu určit počet jedinečných hodnot pro t1c2_index indexu.
SELECT COUNT(DISTINCT [Col2])
FROM t_hk;
Pokud vytváříte novou tabulku, budete muset před nasazením odhadnout velikost pole nebo shromáždit data z testování.
Informace o tom, jak fungují hash indexy v In-Memory tabulkách optimalizovaných pro paměť OLTP, viz Hash Indexy.
Nastavení velikosti pole indexu hash
Velikost pole hash je nastavena (bucket_count= value)
kde value
je celočíselná hodnota větší než nula. Pokud value
není mocninou 2, skutečný počet bucket_count se zaokrouhlí nahoru na nejbližší vyšší mocninu 2. V naší ukázkové tabulce (bucket_count = 5 000 000), protože 5 000 000 není mocnina 2, skutečný počet segmentů se zaokrouhluje na 8 388 608 (2^23). Při výpočtu paměti potřebné pro pole hash je nutné použít toto číslo, nikoli 5 000 000.
V našem příkladu je tedy paměť potřebná pro každé pole hash:
8 388 608 * 8 = 2^23 * 8 = 2^23 * 2^3 = 2^26 = 67 108 864 nebo přibližně 64 MB.
Vzhledem k tomu, že máme tři indexy hash, paměť potřebná pro indexy hash je 3 × 64 MB = 192 MB.
Paměť pro neclusterované indexy
Neclusterované indexy se implementují jako Bw-stromy s vnitřními uzly obsahujícími hodnotu indexu a ukazatele na následující uzly. Uzly typu list obsahují hodnotu indexu a ukazatel na řádek tabulky v paměti.
Na rozdíl od indexů hash nemají neclusterované indexy pevnou velikost kontejneru. Index roste a zmenšuje se dynamicky s daty.
Paměť potřebnou neclusterovanými indexy je možné vypočítat následujícím způsobem:
přidělená paměť ne-listovým uzlům
V případě typické konfigurace je paměť přidělená uzlům mimo list malé procento celkové paměti, kterou index přijímá. To je tak malé, že se dá bezpečně ignorovat.Paměť pro listové uzly
Uzly typu list mají jeden řádek pro každý jedinečný klíč v tabulce, který odkazuje na datové řádky s tímto jedinečným klíčem. Pokud máte více řádků se stejným klíčem (tj. nemáte jedinečný neclusterovaný index), je v uzlu typu list indexu pouze jeden řádek, který odkazuje na jeden z řádků s ostatními řádky propojenými mezi sebou. Celková požadovaná paměť proto může být přibližná takto:- paměťProNeKlastrovanýIndex = (velikostUkazatele + součet(velikostiDatovýchTypůKlíčovýchSloupců)) * řádkySUnikátnímiKlíči
Neclusterované indexy jsou nejlepší při použití pro vyhledávání rozsahu, jak je znázorněno následujícím dotazem:
SELECT * FROM t_hk
WHERE c2 > 5;
Paměť pro verzování řádků
Aby nedocházelo k zámkům, In-Memory OLTP používá při aktualizaci nebo odstraňování řádků optimistickou souběžnost. To znamená, že při aktualizaci řádku se vytvoří jiná verze řádku. Odstranění jsou navíc logické – existující řádek se označí jako odstraněný, ale neodebere se okamžitě. Systém udržuje staré verze řádků (včetně odstraněných řádků) dostupné, dokud všechny transakce, které by mohly tuto verzi použít, nedokončily provádění.
Vzhledem k tomu, že v paměti může být kdykoli mnohem více řádků čekajících na cyklus uvolňování paměti, musíte mít dostatečnou paměť, aby pojmula tyto další řádky.
Počet řádků navíc se dá odhadnout tak, že vynásobíte maximální počet aktualizací a odstranění řádků za sekundu a pak ho vynásobíte počtem sekund, které nejdelší transakce trvá (minimálně 1).
Tato hodnota se pak vynásobí velikostí řádku, abyste získali počet bajtů, které potřebujete pro správu verzí řádků.
rowVersions = durationOfLongestTransactionInSeconds * peakNumberOfRowUpdatesOrDeletesPerSecond
Požadavky na paměť pro zastaralé řádky se pak odhadují vynásobením počtu zastaralých řádků velikostí řádku tabulky optimalizované pro paměť (viz Paměť pro tabulku výše).
memoryForRowVersions = rowVersions * rowSize
Paměť pro proměnné tabulky
Paměť používaná pro proměnnou tabulky se uvolní pouze v případě, že proměnná tabulky přestane být oborem. Odstraněné řádky, včetně těch odstraněných v rámci aktualizace, z proměnné tabulky nepodléhají procesu uvolňování paměti. Dokud proměnná tabulky neopustí rozsah, neuvolní se žádná paměť.
Proměnné tabulky definované ve velké dávce SQL, které se používají v mnoha transakcích na rozdíl od těch s oborem procedury, mohou spotřebovávat hodně paměti. Vzhledem k tomu, že nejsou automaticky uvolňovány z paměti, mohou odstraněné řádky v proměnné tabulky spotřebovat mnoho paměti a snižovat výkon, protože operace čtení musí procházet přes tyto odstraněné řádky.
Paměť pro růst
Výše uvedené výpočty odhadují potřeby paměti pro tabulku, jak v současnosti existuje. Kromě této paměti je potřeba odhadnout růst tabulky a poskytnout dostatek paměti pro přizpůsobení tohoto růstu. Pokud například očekáváte 10% růstu, pak musíte vynásobit výsledky z výše uvedeného číslem 1,1, abyste získali celkovou paměť potřebnou pro vaši tabulku.
Viz také
Migrace na In-Memory OLTP