Megosztás a következőn keresztül:


Táblázat- és sorméret memóriaoptimalizált táblákban

A következőkre vonatkozik:SQL ServerAzure SQL DatabaseAzure SQL Kezelt Példány

Az SQL Server 2016 (13.x) előtt a memóriaoptimalizált táblák sorba rendezett adatmérete nem lehet hosszabb, mint 8060 bájt. Az SQL Server 2016-tól (13.x) és az Azure SQL Database-ben azonban létrehozhat egy memóriaoptimalizált táblát, amely több nagy oszlopból (például több varbinary(8000) oszlopból) és LOB-oszlopokból (azaz varbinary(max), varchar(max)és nvarchar(max)) áll, és rajtuk műveleteket hajthat végre natívan lefordított Transact-SQL (T-SQL) modulok és táblázattípusoknak a használatával.

A 8060 bájtos sorméretkorlátba nem illő oszlopok külön belső táblázatban vannak elhelyezve. Minden soron kívüli oszlopnak van egy megfelelő belső táblázata, amely egyetlen nemclustered indexet tartalmaz. A soron kívüli oszlopokhoz használt belső táblákkal kapcsolatos részletekért lásd: sys.memory_optimized_tables_internal_attributes.

Vannak olyan forgatókönyvek, amelyekben hasznos a sor és a tábla méretének kiszámítása:

  • Mennyi memóriát használ egy tábla.

    • A táblázat által használt memória mennyisége nem számítható ki pontosan. Számos tényező befolyásolja a felhasznált memória mennyiségét. Olyan tényezők, mint a lapalapú memóriafoglalás, a lokalitás, a gyorsítótárazás és a kitöltés. Emellett a sorok több olyan verziója is, amelyekhez aktív tranzakciók vannak társítva, vagy amelyek szemétgyűjtésre várnak.

    • A táblázatban szereplő adatokhoz és indexekhez szükséges minimális méretet a jelen cikk későbbi részében tárgyalt <table size>számítása adja meg.

    • A memóriahasználat kiszámítása legjobb esetben közelítés, és ajánlott a kapacitástervezést belefoglalni az üzembehelyezési tervekbe.

  • Egy sor adatmérete, és illeszkedik a 8060 bájtos sorméret korlátozásához? Ezeknek a kérdéseknek a megválaszolásához használja a <row body size>számítását, amelyet a cikk későbbi részében tárgyalunk.

A memóriaoptimalizált táblák sorokat és indexeket tartalmazó gyűjteményből állnak, amelyek a sorokra mutató mutatókat tartalmaznak. Az alábbi ábra egy indexeket és sorokat tartalmazó táblázatot mutat be, amely viszont sorfejlécekkel és -testekkel rendelkezik:

Memóriaoptimalizált táblázat diagramja.

Számítási tábla mérete

Egy tábla memóriabeli mérete bájtban a következőképpen lesz kiszámítva:

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

A kivonatindex mérete a tábla létrehozásakor rögzített, és a tényleges vödrök számától függ. Az indexdefinícióval megadott bucket_count a legközelebbi kettő hatványára kerekítve kapja meg a tényleges vödrök számát. Ha például a megadott bucket_count érték 100000, az index tényleges vödörszáma 131072.

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

A nem csoportosított index mérete körülbelül <row count> * <index key size>.

A sorméret kiszámítása a fejléc és a törzs összeadásával történik.

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

Számítsa ki a sor törzsének méretét

A memóriaoptimalizált táblázat sorai a következő összetevőkkel rendelkeznek:

  • A sorfejléc tartalmazza a sorverziók implementálásához szükséges időbélyeget. A sorfejléc az indexmutatót is tartalmazza a sorláncolás implementálásához a kivonatgyűjtőkben (korábban leírtak szerint).

  • A sortörzs tartalmazza a tényleges oszlopadatokat, amelyek olyan kiegészítő információkat tartalmaznak, mint a null értékű oszlopok null tömbje és a változó hosszúságú adattípusok eltolástömbje.

Az alábbi ábra egy két indexet tartalmazó táblázat sorstruktúráját mutatja be:

Két indexet tartalmazó táblázat sorszerkezetének diagramja.

A kezdő és a záró időbélyeg azt az időszakot jelzi, amelyben egy adott sorverzió érvényes. Az ebben az intervallumban kezdődő tranzakciók láthatják ezt a sorverziót. További információ: Tranzakciók Memory-Optimized táblákkal.

Az indexmutatók a hash vödörhöz tartozó lánc következő sorára mutatnak. Az alábbi ábra egy tábla szerkezetét mutatja be két oszloptal (név, város) és két indexkel, egy az oszlopnévvel és egy az oszlop városával.

Két oszlopot és indexet tartalmazó táblázat szerkezetének diagramja.

Ebben az ábrán a John és a Jane nevek az első vödörbe kerülnek. Susan le van képezve a második vödörbe. A városok Beijing és Bogota az első vödörbe vannak hash-elve. A Paris és Prague a második vödörbe van hashelve.

Így a névkivonat-index láncai a következők:

  • Első gyűjtő: (John, Beijing); (John, Paris); (Jane, Prague)
  • Második gyűjtő: (Susan, Bogota)

A városindex láncai a következők:

  • Első gyűjtő: (John, Beijing), (Susan, Bogota)
  • Második gyűjtő: (John, Paris), (Jane, Prague)

A záró időbélyeg ∞ (végtelen) azt jelzi, hogy ez a sor jelenleg érvényes verziója. A sor nem lett frissítve vagy törölve, mivel ez a sorverzió meg lett írva.

A 200-nál hosszabb ideig a táblázat a következő sorokat tartalmazza:

Név Város
John Peking
Jane Prága

Azonban bármelyik aktív tranzakció, amelynek kezdési ideje 100, tekintse meg a táblázat következő verzióját:

Név Város
John Párizs
Jane Prága
Susan Bogota

A <row body size> kiszámítását az alábbi táblázat ismerteti.

A sor törzsmérete két különböző számítást tartalmaz: a számított méretet és a tényleges méretet:

  • A számított sor törzsméretéveljelöléssel ellátott számított méret határozza meg, hogy túllépte-e a 8060 bájtos sorméretkorlátot.

  • A tényleges méret, amelyet a sortörzs tényleges méretekéntjelöltek, a sor testének tényleges tárolási mérete a memóriában és az ellenőrzőpont-fájlokban.

A kiszámított sor törzsmérete és a tényleges sor törzsmérete hasonló módon van kiszámítva. Az egyetlen különbség a (n)varchar(i) és varbinary(i) oszlopok méretének kiszámítása, ahogyan az az alábbi táblázat alján is látható. A kiszámított sor törzsmérete a deklarált méretet i az oszlop méreteként, míg a tényleges sor törzsmérete az adatok tényleges méretét használja.

Az alábbi táblázat leírja a sor törzsméretének kiszámítását, amely <actual row body size> = SUM(<size of shallow types>) + 2 + 2 * <number of deep type columns>-ként van megadva.

Szakasz Méret Megjegyzések
sekély típusú oszlopok SUM(<size of shallow types>). Az egyes típusok bájtban megadott mérete a következő:

bit: 1
tinyint: 1
smallint: 2
int: 4
valós: 4
Littledatetime: 4
kevés pénz: 4
bigint: 8
Időpont:8
Dátumidő2: 8
lebegőpontos: 8
pénz: 8
numerikus (pontosság <= 18): 8
idő: 8
szám(pontosság > 18): 16
uniqueidentifier: 16
Sekély oszloptérköz A lehetséges értékek a következők:

1 ha vannak mély típusú oszlopok, és a sekély oszlopok teljes adatmérete páratlan szám.

0 egyébként
A mély típusok a (var)bináris és a (n)(var)char.
Eltolási tömb mély típusú oszlopokhoz A lehetséges értékek a következők:

0, ha nincsenek mély típusú oszlopok

2 + 2 * <number of deep type columns> egyébként
A mély típusok a (var)bináris és a (n)(var)char.
Üres tömb <number of nullable columns> / 8 teljes bájtra kerekítve. A tömb null értékű oszloponként 1 bitet tartalmaz. Ez fel van kerekítve egész bájtokra.
Null tömb kitöltés A lehetséges értékek a következők:

1 ha vannak mély típusú oszlopok, és a NULL tömb mérete páratlan számú bájt.
0 egyébként
A mély típusok a (var)bináris és a (n)(var)char.
párnázási Ha nincsenek mély típusú oszlopok: 0

Mély típusú oszlopok esetén a rendszer 0–7 bájtnyi kitöltést ad hozzá a sekély oszlop által megkövetelt legnagyobb igazítás alapján. Minden sekély oszlophoz a korábban dokumentált méretnek megfelelő igazítás szükséges, azzal a kivételsel, hogy a GUID-oszlopoknak 1 bájt (nem 16) igazításra van szükségük, a numerikus oszlopoknak pedig mindig 8 bájt (soha 16) igazításra van szükségük. Az összes sekély oszlop között a legnagyobb igazítási követelmény van használatban. A rendszer 0–7 bájtnyi kitöltést ad hozzá úgy, hogy az eddigi teljes méret (a mély típusú oszlopok nélkül) a szükséges igazítás többszöröse legyen.
A mély típusok a (var)bináris és a (n)(var)char.
Rögzített hosszúságú mély típusú oszlopok SUM(<size of fixed length deep type columns>)

Az egyes oszlopok mérete a következő:

i karakter (i) és bináris (i).
2 * i nchar(i)
A rögzített hosszúságú oszlopok lehetnek char(i), nchar(i)vagy binary(i)típusú.
Változó hosszúságú mély típusú oszlopok számított méret SUM(<computed size of variable length deep type columns>)

Az egyes oszlopok számított mérete a következő:

i varchar(i) és varbinary(i)

2 * i nvarchar(i)
Ez a sor csak a számított sor törzsméretére vonatkozik.

A változó hosszúságú mély típusú oszlopok varchar(i), nvarchar(i)vagy varbinary(i). A kiszámított méretet az oszlop maximális hossza (i) határozza meg.
Változó hosszúságú mély típusú oszlopok tényleges méret SUM(<actual size of variable length deep type columns>)

Az egyes oszlopok tényleges mérete a következő:

n, ahol n az oszlopban tárolt karakterek száma, varchar(és).

2 * n, ahol n az oszlopban tárolt karakterek száma, nvarchar(és).

n, ahol n az oszlopban tárolt bájtok száma, a varbinary(és)számára.
Ez a sor csak tényleges sortörzsméretrevonatkozik.

A tényleges méretet a sor oszlopaiban tárolt adatok határozzák meg.

Példa: Táblázat- és sorméret számítása

Kivonatindexek esetén a tényleges gyűjtők száma a legközelebbi kettő hatványára lesz kerekítve. Ha például a megadott bucket_count 100000, az index tényleges gyűjtőszáma 131072.

Vegyünk egy Megrendelések táblát a következő definícióval:

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

Ez a tábla egy kivonatindexet és egy nemclustered indexet (az elsődleges kulcsot) tartalmaz. Emellett három rögzített hosszúságú oszlopot és egy változó hosszúságú oszlopot is tartalmaz, az egyik oszlop null értékű (OrderDescription). Tegyük fel, hogy a Orders táblázat 8379 sort tartalmaz, és az OrderDescription oszlop értékeinek átlagos hossza 78 karakter.

A táblázat méretének meghatározásához először határozza meg az indexek méretét. Mindkét index bucket_count 10000-ként van megadva. Ez a 2 legközelebbi hatványára van kerekítve, ami 16384. Ezért a Orders tábla indexeinek teljes mérete a következő:

8 * 16384 = 131072 bytes

A tábla adatmérete továbbra is a következő:

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

(A példatábla 8379 sort tartalmaz.) Most a következőt értünk el:

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

Következő lépésként számítsuk ki <actual row body size>:

  • Sekély típusú oszlopok:

    SUM(<size of shallow types>) = 4 <int> + 4 <int> + 8 <datetime> = 16
    
  • A sekély oszloppárna 0, mivel a teljes sekély oszlopméret egyenletes.

  • Mély típusú oszlopok eltolási tömbje:

    2 + 2 * <number of deep type columns> = 2 + 2 * 1 = 4
    
  • NULL tömb = 1

  • NULL tömbpárnázás = 1, mivel a NULL tömb mérete páratlan, és van egy mély típusú oszlop.

  • Tömőanyag

    • A 8 a legnagyobb igazítási követelmény
    • A méret eddig 16 + 0 + 4 + 1 + 1 = 22
    • A 8 legközelebbi többszöröse 24
    • A teljes kitöltés 24 – 22 = 2 bájt
  • Nincsenek rögzített hosszúságú mély típusú oszlopok (Rögzített hosszúságú mély típusú oszlopok: 0.).

  • A mély típusú oszlop tényleges mérete 2 * 78 = 156. Az egyetlen mélytípusú oszlop OrderDescriptionnvarchartípussal rendelkezik.

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

A számítás elvégzéséhez:

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

A teljes táblaméret a memóriában így körülbelül 2 megabájt. Ez nem veszi figyelembe a memórialefoglalás esetleges többletterhelését, valamint a táblához hozzáférő tranzakciókhoz szükséges sorverziókat.

A tábla és indexei által lefoglalt és felhasznált tényleges memória a következő lekérdezéssel kérhető le:

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

Az oszlopok soron kívüli korlátozásai

A memóriaoptimalizált táblák soron kívüli oszlopainak használatára vonatkozó bizonyos korlátozások és kikötések a következők:

  • Ha egy memóriaoptimalizált táblán oszlopcentrikus index található, akkor az összes oszlopnak sorba kell illeszkednie.
  • Minden indexkulcsoszlopot sorban kell tárolni. Ha az indexkulcs oszlopa nem fér el a sorban, az index hozzáadása sikertelen lesz.
  • A memóriaoptimalizált táblázat soron kívüli oszlopokkal történő módosítására vonatkozó figyelmeztetések.
  • A LOB-k esetében a méretkorlátozás a lemezalapú táblákra vonatkozik (2 GB-os korlát a LOB-értékekre).
  • Az optimális teljesítmény érdekében azt javasoljuk, hogy a legtöbb oszlop 8060 bájton belül illeszkedjen.
  • A soron kívüli adatok túl sok memóriát és/vagy lemezhasználatot okozhatnak.