Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Dotyczy:SQL Server
Azure SQL Database
Azure SQL Managed Instance
Tabele zoptymalizowane pod kątem pamięci wymagają wystarczającej ilości pamięci, aby zachować wszystkie wiersze i indeksy w pamięci. Ponieważ pamięć jest zasobem skończonym, ważne jest, aby zrozumieć użycie pamięci w systemie i zarządzać nim. Tematy w tej sekcji obejmują typowe scenariusze użycia pamięci i zarządzania.
Niezależnie od tego, czy tworzysz nową tabelę zoptymalizowaną pod kątem pamięci, czy migrujesz istniejącą tabelę opartą na dyskach do tabeli In-Memory zoptymalizowanej pod kątem pamięci OLTP, ważne jest, aby mieć uzasadnione oszacowanie potrzeb związanych z pamięcią każdej tabeli, dzięki czemu można aprowizować serwer z wystarczającą ilością pamięci. W tej sekcji opisano sposób szacowania ilości pamięci potrzebnej do przechowywania danych dla tabeli zoptymalizowanej pod kątem pamięci.
Jeśli rozważasz migrację z tabel opartych na dyskach do tabel zoptymalizowanych pod kątem pamięci, zanim przejdziesz do tego tematu, zobacz temat Określanie, czy tabela lub procedura składowana powinna zostać przeniesiona do In-Memory olTP, aby uzyskać wskazówki, które tabele najlepiej migrować. Wszystkie tematy w Migrowanie do In-Memory OLTP zawierają wskazówki dotyczące migracji z tabel opartych na dyskach do tabel zoptymalizowanych pod kątem pamięci.
Podstawowe wskazówki dotyczące szacowania wymagań dotyczących pamięci
Począwszy od programu SQL Server 2016 (13.x), nie ma limitu rozmiaru tabel zoptymalizowanych pod kątem pamięci, chociaż tabele muszą zmieścić się w pamięci. W programie SQL Server 2014 (12.x) obsługiwany rozmiar danych wynosi 256 GB dla tabel SCHEMA_AND_DATA.
Rozmiar tabeli zoptymalizowanej pod kątem pamięci odpowiada rozmiarowi danych oraz pewne obciążenie nagłówków wierszy. Podczas migracji tabeli opartej na dysku do zoptymalizowanej pod kątem pamięci rozmiar tabeli zoptymalizowanej pod kątem pamięci będzie w przybliżeniu odpowiadać rozmiarowi indeksu klastrowanego lub sterty oryginalnej tabeli opartej na dyskach.
Indeksy w tabelach zoptymalizowanych pod kątem pamięci są zwykle mniejsze niż indeksy nieklastrowane w tabelach opartych na dyskach. Rozmiar indeksów nieklastrowanych jest w przybliżeniu [primary key size] * [row count]
. Rozmiar indeksów skrótu jest [bucket count] * 8 bytes
.
Jeśli istnieje aktywne obciążenie, wymagana jest dodatkowa pamięć do uwzględnienia przechowywania wersji wierszy i różnych operacji. Ilość pamięci potrzebnej w praktyce zależy od obciążenia, ale aby zapewnić bezpieczeństwo, zaleca się rozpoczęcie od dwóch razy oczekiwanych rozmiarów tabel i indeksów zoptymalizowanych pod kątem pamięci oraz obserwowania wymagań dotyczących pamięci w praktyce. Obciążenie związane z wersjonowaniem wierszy zawsze zależy od charakterystyki obciążenia — szczególnie transakcje długotrwałe zwiększają to obciążenie. W przypadku większości obciążeń korzystających z większych baz danych (np. >100 GB) obciążenie zwykle jest ograniczone (25% lub mniej).
Szczegółowe obliczenia wymagań dotyczących pamięci
pamięć dla indeksów
pamięć na potrzeby przechowywania wersji wierszy
Przykładowa tabela zoptymalizowana pod kątem pamięci
Rozważmy następujący schemat tabeli zoptymalizowany pod kątem pamięci:
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
Korzystając z tego schematu, określimy minimalną ilość pamięci wymaganą dla tej tabeli zoptymalizowanej pod kątem pamięci.
Pamięć dla tabeli
Wiersz tabeli zoptymalizowany pod kątem pamięci składa się z trzech części:
znaczniki czasu
Nagłówka wiersza/znaczniki czasu = 24 bajty.wskaźniki indeksu
Dla każdego indeksu skrótu w tabeli każdy wiersz ma wskaźnik adresu 8-bajtowego do następnego wiersza w indeksie. Ponieważ istnieją cztery indeksy, każdy wiersz przydziela 32 bajty dla wskaźników indeksu (wskaźnik 8 bajtów dla każdego indeksu).data
Rozmiar części danych wiersza jest określany przez sumowanie rozmiaru typu dla każdej kolumny danych. W naszej tabeli mamy pięć liczb całkowitych 4-bajtowych, trzy 50-bajtowe kolumny znaków i 30-bajtową kolumnę znaków. Dlatego część danych każdego wiersza to 4 + 4 + 4 + 4 + 4 + 4 + 50 + 50 + 30 + 50 lub 200 bajtów.
Poniżej przedstawiono obliczenia rozmiaru dla 5000 000 wierszy (5 milionów) w tabeli zoptymalizowanej pod kątem pamięci. Łączna ilość pamięci używanej przez wiersze danych jest szacowana w następujący sposób:
Pamięć dotycząca wierszy tabeli
Z powyższych obliczeń rozmiar każdego wiersza w tabeli zoptymalizowanej pod kątem pamięci wynosi 24 + 32 + 200 lub 256 bajtów. Ponieważ mamy 5 milionów wierszy, tabela będzie zużywać 5000 000 * 256 bajtów lub 1280 000 000 bajtów — około 1,28 GB.
Pamięć dla indeksów
Pamięć dla każdego indeksu skrótu
Każdy indeks skrótu jest tablicą skrótów 8-bajtowych wskaźników adresowych. Rozmiar tablicy jest najlepiej określany przez liczbę unikatowych wartości indeksu dla tego indeksu — np. liczba unikatowych wartości Col2 jest dobrym punktem wyjścia dla rozmiaru tablicy dla t1c2_index. Tablica skrótów, która jest zbyt duża, marnuje pamięć. Tablica skrótów, która jest zbyt mała, spowalnia wydajność, ponieważ istnieje zbyt wiele kolizji według wartości indeksu, które mają skrót do tego samego indeksu.
Indeksy hashowe umożliwiają bardzo szybkie zapytania o równość, takie jak:
SELECT * FROM t_hk
WHERE Col2 = 3;
Indeksy nieklastrowane są szybsze w przypadku wyszukiwania zakresów, takich jak:
SELECT * FROM t_hk
WHERE Col2 >= 3;
Jeśli migrujesz tabelę opartą na dyskach, możesz użyć poniższej metody, aby określić liczbę unikatowych wartości dla t1c2_index indeksu.
SELECT COUNT(DISTINCT [Col2])
FROM t_hk;
Jeśli tworzysz nową tabelę, musisz oszacować rozmiar tablicy lub zebrać dane z testów przed wdrożeniem.
Aby uzyskać informacje na temat sposobu działania indeksów skrótów w tabelach zoptymalizowanych pod kątem pamięci OLTP In-Memory, zobacz Indeksy Skrótów.
Ustawianie rozmiaru tablicy indeksów skrótów
Rozmiar tablicy skrótów jest ustawiany przez (bucket_count= value)
, gdzie value
jest wartością całkowitą większą niż zero. Jeśli value
nie jest potęgą 2, rzeczywista wartość bucket_count jest zaokrąglana do najbliższej wyższej potęgi 2. W naszej przykładowej tabeli (bucket_count = 5000000), ponieważ 5 000 000 nie jest potęgą 2, rzeczywista liczba zasobników zaokrągla się do 8 388 608 (2^23). Należy użyć tej liczby, a nie 5000 000 podczas obliczania pamięci wymaganej przez tablicę skrótów.
W związku z tym w naszym przykładzie pamięć wymagana dla każdej tablicy skrótów to:
8,388,608 * 8 = 2^23 * 8 = 2^23 * 2^3 = 2^26 = 67,108,864 lub około 64 MB.
Ponieważ mamy trzy indeksy skrótów, pamięć wymagana dla indeksów skrótu wynosi 3 * 64 MB = 192 MB.
Pamięć dla indeksów nieklastrowanych
Indeksy nieklastrowane są implementowane jako drzewa Bw z węzłami wewnętrznymi zawierającymi wartość indeksu i wskaźniki do kolejnych węzłów. Węzły liściowe zawierają wartość indeksu i wskaźnik do wiersza tabeli w pamięci.
W przeciwieństwie do indeksów skrótów indeksy nieklastrowane nie mają stałego rozmiaru zasobnika. Indeks rośnie i zmniejsza się dynamicznie wraz z danymi.
Pamięć wymagana przez indeksy nieklastrowane można obliczyć w następujący sposób:
pamięć przydzielona do węzłów niebędących liścieniowymi
W przypadku typowej konfiguracji pamięć przydzielona do węzłów innych niż liścia jest niewielką częścią ogólnej pamięci pobranej przez indeks. Jest to tak małe, że można je bezpiecznie zignorować.pamięć dla węzłów liści
Węzły liścia mają jeden wiersz dla każdego unikatowego klucza w tabeli, który wskazuje wiersze danych za pomocą tego unikatowego klucza. Jeśli masz wiele wierszy z tym samym kluczem (tj. masz nieunikalny indeks nieklastrowany), w węźle liścia indeksu znajduje się tylko jeden wiersz, który wskazuje na jeden z wierszy, a pozostałe wiersze są połączone ze sobą. W związku z tym łączna ilość wymaganej pamięci może być przybliżona przez:- pamięćDlaIndeksuNieklastrowego = (rozmiarWskaźnika + suma(rozmiaryTypówDanychKolumnKluczowych)) * wierszeZUunikalnymiKluczami
Indeksy nieklastrowane najlepiej nadają się do wyszukiwania zakresów, co jest przykładem następującego zapytania:
SELECT * FROM t_hk
WHERE c2 > 5;
Pamięć na potrzeby przechowywania wersji wierszy
Aby uniknąć blokad, In-Memory OLTP używa optymistycznej współbieżności podczas aktualizowania lub usuwania wierszy. Oznacza to, że po zaktualizowaniu wiersza zostanie utworzona inna wersja wiersza. Ponadto usunięcia są logiczne — istniejący wiersz jest oznaczony jako usunięty, ale nie jest usuwany natychmiast. System przechowuje stare wersje wierszy (w tym usunięte wiersze) do momentu zakończenia wykonywania wszystkich transakcji, które mogą korzystać z wersji.
Ponieważ w każdej chwili może istnieć wiele więcej wierszy w pamięci oczekujących na zwolnienie pamięci przez cykl odzyskiwania pamięci, musisz mieć wystarczającą ilość pamięci, aby pomieścić te inne wiersze.
Liczbę dodatkowych wierszy można oszacować, obliczając maksymalną liczbę aktualizacji wierszy i usuwania na sekundę, a następnie mnożąc je przez liczbę sekund najdłuższej transakcji (co najmniej 1).
Ta wartość jest następnie mnożona przez rozmiar wiersza, aby uzyskać liczbę bajtów potrzebnych do przechowywania wersji wierszy.
rowVersions = durationOfLongestTransactionInSeconds * peakNumberOfRowUpdatesOrDeletesPerSecond
Zapotrzebowanie na nieaktualne wiersze jest następnie szacowane przez pomnożenie liczby nieaktualnych wierszy według rozmiaru wiersza tabeli zoptymalizowanego pod kątem pamięci (zobacz Pamięć dla tabeli powyżej).
memoryForRowVersions = rowVersions * rowSize
Pamięć dla zmiennych tabeli
Pamięć używana dla zmiennej tabeli jest zwalniana tylko wtedy, gdy zmienna tabeli wykracza poza zakres. Usunięte wiersze, w tym wiersze usunięte w ramach aktualizacji, ze zmiennej tabeli nie podlegają wyrzucaniu elementów bezużytecznych. Żadna pamięć nie jest zwalniana, dopóki zmienna tabeli nie opuści zakresu.
Zmienne tabeli zdefiniowane w dużej partii SQL, w przeciwieństwie do zakresu procedury, które są używane w wielu transakcjach, mogą zużywać dużo pamięci. Ponieważ nie są one zbierane, usunięte wiersze w zmiennej tabeli mogą zużywać dużo pamięci i obniżyć wydajność, ponieważ operacje odczytu muszą skanować obok usuniętych wierszy.
Pamięć na potrzeby wzrostu
Powyższe obliczenia szacują zapotrzebowanie na pamięć dla tabeli w jej obecnym stanie. Oprócz tej pamięci należy oszacować wzrost tabeli i zapewnić wystarczającą ilość pamięci, aby uwzględnić ten wzrost. Na przykład, jeśli przewidujesz wzrost o 10%, musisz pomnożyć wyniki z powyższych przez 1,1, aby uzyskać łączną ilość pamięci potrzebną do tabeli.