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
Przed programem SQL Server 2016 (13.x) rozmiar danych w wierszu tabeli zoptymalizowanej pod kątem pamięci nie może być dłuższy niż 8060 bajtów. Jednak począwszy od programu SQL Server 2016 (13.x) i usługi Azure SQL Database, można utworzyć tabelę zoptymalizowaną pod kątem pamięci z wieloma dużymi kolumnami (na przykład wiele kolumn varbinary(8000)) i loB (czyli varbinary(max), varchar(max)i nvarchar(max)) i wykonywać operacje na nich przy użyciu natywnie skompilowanych modułów Transact-SQL (T-SQL) i typów tabel.
Kolumny, które nie mieszczą się w limicie rozmiaru wiersza 8060 bajtów, są umieszczane poza wierszem w oddzielnej tabeli wewnętrznej. Każda kolumna poza wierszem ma odpowiadającą tabelę wewnętrzną, która z kolei ma pojedynczy indeks nieklastrowany. Aby uzyskać szczegółowe informacje o tych tabelach wewnętrznych używanych do przechowywania kolumn poza wierszem, zobacz sys.memory_optimized_tables_internal_attributes.
Istnieją pewne scenariusze, w których warto obliczyć rozmiar wiersza i tabeli:
Ile pamięci używa tabela.
Nie można dokładnie obliczyć ilości pamięci używanej przez tabelę. Wiele czynników wpływa na ilość używanej pamięci. Czynniki takie jak alokacja pamięci na podstawie strony, lokalność, buforowanie i dopełnienie. Ponadto wiele wersji wierszy, które są związane z aktywnymi transakcjami lub czekają na zbieranie nieużywanej pamięci.
Minimalny rozmiar wymagany dla danych i indeksów w tabeli jest podawany przez obliczenie dla
<table size>
, omówionego w dalszej części tego artykułu.Obliczanie użycia pamięci jest najlepszym przybliżeniem i zaleca się uwzględnienie planowania pojemności w planach wdrożenia.
Rozmiar danych wiersza i czy mieści się w ograniczeniu rozmiaru wiersza 8060 bajtów? Aby odpowiedzieć na te pytania, użyj obliczeń dla
<row body size>
, omówionej w dalszej części tego artykułu.
Tabela zoptymalizowana pod kątem pamięci składa się z kolekcji wierszy i indeksów zawierających wskaźniki do wierszy. Na poniższej ilustracji przedstawiono tabelę z indeksami i wierszami, które z kolei mają nagłówki wierszy i treści:
Oblicz rozmiar tabeli
Rozmiar w pamięci tabeli w bajtach jest obliczany w następujący sposób:
<table size> = <size of index 1> + ... + <size of index n> + (<row size> * <row count>)
Rozmiar indeksu skrótu jest stały w czasie tworzenia tabeli i zależy od rzeczywistej liczby wiader.
bucket_count
określony definicją indeksu jest zaokrąglany do najbliższej potęgi liczby 2, aby uzyskać rzeczywistą liczbę zasobników. Na przykład, jeśli określona bucket_count
wynosi 100000, to rzeczywista liczba zasobników dla indeksu wynosi 131072.
<hash index size> = 8 * <actual bucket count>
Rozmiar indeksu nieklastrowanego jest w przybliżeniu rzędu wielkości <row count> * <index key size>
.
Rozmiar wiersza jest obliczany przez dodanie nagłówka i treści:
<row size> = <row header size> + <actual row body size>
<row header size> = 24 + 8 * <number of indexes>
Rozmiar treści wiersza obliczeniowego
Wiersze w tabeli zoptymalizowanej pod kątem pamięci mają następujące składniki:
Nagłówek wiersza zawiera znacznik czasu niezbędny do zaimplementowania wersjonowania wierszy. Nagłówek wiersza zawiera również wskaźnik indeksu w celu zaimplementowania łańcucha wierszy w zasobnikach skrótów (opisanych wcześniej).
Treść wiersza zawiera rzeczywiste dane kolumn, w tym niektóre informacje pomocnicze, takie jak tablica null dla kolumn dopuszczających wartość null i tablica przesunięcia dla typów danych o zmiennej długości.
Na poniższej ilustracji przedstawiono strukturę wierszy dla tabeli zawierającej dwa indeksy:
Znaczniki czasu rozpoczęcia i zakończenia wskazują okres, w którym określona wersja wiersza jest prawidłowa. Transakcje rozpoczynające się w tym interwale mogą zobaczyć tę wersję wiersza. Aby uzyskać więcej informacji, zobacz Transakcje z tabelami Memory-Optimized.
Wskaźniki indeksu wskazują następny wiersz w łańcuchu należącym do zasobnika skrótu. Na poniższej ilustracji przedstawiono strukturę tabeli z dwiema kolumnami (nazwa, miasto) i dwoma indeksami, jedną w nazwie kolumny i jedną w mieście kolumny.
Na tym rysunku nazwy John
i Jane
są zhashowane do pierwszego wiadra.
Susan
jest haszowany do drugiego zasobnika. Miasta Beijing
i Bogota
zostały zhaszowane do pierwszego segmentu.
Paris
i Prague
zostały zahaszowane do drugiego wiadra.
W związku z tym łańcuchy indeksu skrótu dla nazwy są następujące:
- Pierwszy zasobnik:
(John, Beijing)
;(John, Paris)
;(Jane, Prague)
- Drugi zasobnik:
(Susan, Bogota)
Łańcuchy indeksu dotyczącego miasta są następujące:
- Pierwszy zasobnik:
(John, Beijing)
,(Susan, Bogota)
- Drugi zasobnik:
(John, Paris)
,(Jane, Prague)
Znacznik czasu zakończenia ∞ (nieskończoność) wskazuje, że jest to aktualnie prawidłowa wersja wiersza. Wiersz nie został zaktualizowany ani usunięty, ponieważ ta wersja wiersza została zapisana.
W przypadku czasu większego niż 200
tabela zawiera następujące wiersze:
Nazwa | Miasto |
---|---|
John | Pekin |
Jane | Praga |
Jednak każda aktywna transakcja z czasem rozpoczęcia 100
, zobacz następującą wersję tabeli:
Nazwa | Miasto |
---|---|
John | Paryż |
Jane | Praga |
Susan | Bogota |
Obliczenie <row body size>
omówiono w poniższej tabeli.
Istnieją dwa różne obliczenia dotyczące rozmiaru treści wiersza: obliczony rozmiar i rzeczywisty rozmiar:
Obliczony rozmiar, oznaczony obliczonym rozmiarem treści wiersza, służy do określenia, czy przekroczono ograniczenie rozmiaru wiersza o rozmiarze 8060 bajtów.
Rzeczywisty rozmiar, oznaczony jako rzeczywisty rozmiar treści wiersza, to rzeczywisty rozmiar przechowywania treści wiersza w pamięci i w plikach punktów kontrolnych.
Zarówno obliczony rozmiar treści wiersza, jak i rzeczywisty rozmiar treści wiersza są obliczane w podobny sposób. Jedyną różnicą jest obliczanie rozmiaru kolumn (n)varchar(i) oraz varbinary(i), co znajduje odzwierciedlenie w dolnej części poniższej tabeli. Obliczony rozmiar treści wiersza używa zadeklarowanego rozmiaru i jako rozmiar kolumny, podczas gdy rzeczywisty rozmiar treści wiersza używa rzeczywistego rozmiaru danych.
W poniższej tabeli opisano obliczenie rozmiaru treści wiersza podanego jako <actual row body size> = SUM(<size of shallow types>) + 2 + 2 * <number of deep type columns>
.
Sekcja | Rozmiar | Komentarze |
---|---|---|
kolumny płytkiego typu |
SUM(<size of shallow types>) . Rozmiar w bajtach poszczególnych typów jest następujący:bit: 1 tinyint: 1 smallint: 2 : 4 rzeczywiste: 4 smalldatetime: 4 małepieniądze: 4 bigint: 8 data i czas: 8 datetime2: 8 zmiennoprzecinkowe: 8 pieniądze: 8 liczbowy (precyzja <= 18): 8 czas: 8 liczbowych (> precyzji 18): 16 uniqueidentifier: 16 |
|
Płytkie wypełnienie kolumny | Możliwe wartości to:1 , jeśli istnieją kolumny typu głębokiego, a łączny rozmiar danych płytkich kolumn jest liczbą nieparzystą.0 w przeciwnym razie |
Typy głębokie to typy (var)binary i (n)(var)char. |
Tablica przesunięcia dla kolumn typu głębokiego | Możliwe wartości to:0 , jeśli nie ma kolumn typu głębokiego2 + 2 * <number of deep type columns> w przeciwnym razie |
Typy głębokie to typy (var)binary i (n)(var)char. |
tablica null |
<number of nullable columns> / 8 zaokrąglone do pełnych bajtów. |
Tablica ma 1 bit na kolumnę, która może przyjąć wartość null. Jest to zaokrąglane do pełnych bajtów. |
wypełnienie tablicy null | Możliwe wartości to:1 , jeśli istnieją kolumny typu głębokiego, a rozmiar tablicy NULL to nieparzysta liczba bajtów.0 w przeciwnym razie |
Typy głębokie to typy (var)binary i (n)(var)char. |
Wypełnienie | Jeśli nie ma kolumn typu głębokiego: 0 W przypadku kolumn typu głębokiego dodawane jest 0–7 bajtów wypełnienia, w zależności od największego wyrównania wymaganego przez kolumnę typu płytkiego. Każda płytka kolumna wymaga wyrównania odpowiadającego jej rozmiarowi, jak opisano wcześniej, z tą różnicą, że kolumny GUID wymagają wyrównania 1 bajtu (a nie 16), a kolumny liczbowe zawsze wymagają wyrównania 8 bajtów (nigdy 16). Największe wymaganie dotyczące wyrównania spośród wszystkich płytkich kolumn jest stosowane. 0 - 7 bajtów wypełnienia jest dodawanych w taki sposób, że całkowity rozmiar do tej pory (bez kolumn typu głębokiego) jest wielokrotnością wymaganego wyrównania. |
Typy głębokie to typy (var)binary i (n)(var)char. |
kolumny głębokiego typu o stałej długości | SUM(<size of fixed length deep type columns>) Rozmiar każdej kolumny jest następujący: i dla char(i) i binary(i).2 * i dla nchar(i) |
Kolumny typu głębokiego o stałej długości to kolumny typu char(i), nchar(i)lub binary(i). |
Kolumny typu głębokiego o zmiennej długości rozmiar obliczony | SUM(<computed size of variable length deep type columns>) Obliczony rozmiar każdej kolumny jest następujący: i dla varchar(i) i varbinary(i)2 * i dla nvarchar(i) |
Ten wiersz został zastosowany tylko do obliczonego rozmiaru treści wiersza. Kolumny typu głębokiego o zmiennej długości to kolumny typu varchar(i), nvarchar(i)lub varbinary(i). Obliczony rozmiar jest określany przez maksymalną długość ( i ) kolumny. |
kolumny typu głębokiego o zmiennej długości rzeczywisty rozmiar | SUM(<actual size of variable length deep type columns>) Rzeczywisty rozmiar każdej kolumny jest następujący: n , gdzie n oznacza liczbę znaków przechowywanych w kolumnie dla varchar(i).2 * n , gdzie n jest liczbą znaków przechowywanych w kolumnie, dla nvarchar(i).n , gdzie n jest liczbą bajtów przechowywanych w kolumnie, dla varbinary(i). |
Ten wiersz dotyczy tylko rzeczywistego rozmiaru ciała wiersza . Rzeczywisty rozmiar jest określany przez dane przechowywane w kolumnach w wierszu. |
Przykład: obliczanie rozmiaru tabeli i wiersza
W przypadku indeksów skrótów rzeczywista liczba kubełków jest zaokrąglona do najbliższej potęgi 2. Jeśli na przykład określona bucket_count
wynosi 100000, rzeczywista liczba zasobników dla indeksu jest 131072.
Rozważ tabelę Orders (Zamówienia) z następującą definicją:
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
Ta tabela zawiera jeden indeks skrótu i indeks nieklastrowany (klucz podstawowy). Ma również trzy kolumny o stałej długości i jedną kolumnę o zmiennej długości, przy czym jedna z kolumn ma atrybut NULL
able (OrderDescription
). Załóżmy, że tabela Orders
ma 8379 wierszy, a średnia długość wartości w kolumnie OrderDescription
wynosi 78 znaków.
Aby określić rozmiar tabeli, najpierw określ rozmiar indeksów.
bucket_count
dla obu indeksów jest określony jako 10000. Jest to zaokrąglane do najbliższej mocy 2: 16384. W związku z tym całkowity rozmiar indeksów dla tabeli Orders
wynosi:
8 * 16384 = 131072 bytes
Pozostaje rozmiar danych tabeli, czyli:
<row size> * <row count> = <row size> * 8379
(Przykładowa tabela zawiera 8379 wierszy). Teraz mamy:
<row size> = <row header size> + <actual row body size>
<row header size> = 24 + 8 * <number of indices> = 24 + 8 * 1 = 32 bytes
Następnie obliczmy <actual row body size>
:
Kolumny płytkiego typu
SUM(<size of shallow types>) = 4 <int> + 4 <int> + 8 <datetime> = 16
Płytkie wypełnienie kolumny wynosi 0, ponieważ łączny płytki rozmiar kolumny jest równy.
Tablica przesunięć dla głębokiego typu kolumn
2 + 2 * <number of deep type columns> = 2 + 2 * 1 = 4
tablica
NULL
= 1NULL
wypełnienie tablicy = 1, ponieważ rozmiar tablicyNULL
jest dziwny i istnieje kolumna typu głębokiego.Dopełnienie
- 8 to największe wymaganie wyrównania
- Rozmiar do tej pory wynosi 16 + 0 + 4 + 1 + 1 = 22
- Najbliższa wielokrotność 8 to 24
- Całkowite wypełnienie wynosi 24–22 = 2 bajty
Nie ma kolumn typu głębokiego o stałej długości (kolumny typu głębokiego o stałej długości: 0).
Rzeczywisty rozmiar kolumny typu głębokiego wynosi 2 * 78 = 156. Kolumna pojedynczego typu głębokiego
OrderDescription
ma typnvarchar
.
<actual row body size> = 24 + 156 = 180 bytes
Aby ukończyć obliczenie:
<row size> = 32 + 180 = 212 bytes
<table size> = 8 * 16384 + 212 * 8379 = 131072 + 1776348 = 1907420
Łączny rozmiar tabeli w pamięci wynosi zatem około 2 megabajty. Nie uwzględnia to potencjalnego obciążenia związanego z alokacją pamięci ani żadnych wersji wierszy wymaganych dla transakcji, które uzyskują dostęp do tej tabeli.
Rzeczywista pamięć przydzielona do tej tabeli i używana przez nią oraz jej indeksy można uzyskać za pomocą następującego zapytania:
SELECT * FROM sys.dm_db_xtp_table_memory_stats
WHERE object_id = object_id('dbo.Orders');
Ograniczenia kolumn poza rzędem
Niektóre ograniczenia i zastrzeżenia dotyczące używania kolumn poza wierszami w tabeli zoptymalizowanej pod kątem pamięci są wymienione w następujący sposób:
- Jeśli istnieje indeks magazynowania kolumn w tabeli zoptymalizowanej pod kątem pamięci, wszystkie kolumny muszą znajdować się w wierszu.
- Wszystkie kolumny klucza indeksu muszą być przechowywane w wierszu. Jeśli kolumna klucza indeksu nie mieści się w wierszu, dodanie indeksu zakończy się niepowodzeniem.
- Zastrzeżenia dotyczące zmiany tabeli zoptymalizowanej pod kątem pamięci przy użyciu kolumn poza wierszem.
- W przypadku obiektów LOB ograniczenie rozmiaru odzwierciedla tabele oparte na dyskach (limit 2 GB dla wartości LOB).
- Aby uzyskać optymalną wydajność, zalecamy, aby większość kolumn mieściła się w ciągu 8060 bajtów.
- Dane poza wierszem mogą powodować nadmierne użycie pamięci i/lub dysku.
Powiązana zawartość
- Przykładowa baza danych usługi In-Memory OLTP