Ukuran tabel dan baris dalam tabel yang dioptimalkan memori

Berlaku untuk:SQL ServerAzure SQL DatabaseAzure SQL Managed Instance

Sebelum SQL Server 2016 (13.x), ukuran data dalam baris tabel yang dioptimalkan memori tidak boleh lebih panjang dari 8.060 byte. Namun, dimulai dengan SQL Server 2016 (13.x), dan di Azure SQL Database, Anda dapat membuat tabel yang dioptimalkan memori dengan beberapa kolom besar (misalnya, beberapa kolom varbinary(8000) dan kolom LOB (yaitu, varbinary(max), varchar(maks), dan nvarchar(maks)) dan melakukan operasi pada kolom tersebut menggunakan modul dan jenis tabel Transact-SQL (T-SQL) yang dikompilasi secara asli.

Kolom yang tidak pas dalam batas ukuran baris 8.060 byte ditempatkan di luar baris, dalam tabel internal terpisah. Setiap kolom off-row memiliki tabel internal yang sesuai, yang pada gilirannya memiliki satu indeks nonclustered. Untuk detail tentang tabel internal ini yang digunakan untuk kolom di luar baris, lihat sys.memory_optimized_tables_internal_attributes.

Ada skenario tertentu di mana berguna untuk menghitung ukuran baris dan tabel:

  • Berapa banyak memori yang digunakan tabel.

    • Jumlah memori yang digunakan oleh tabel tidak dapat dihitung dengan tepat. Banyak faktor yang memengaruhi jumlah memori yang digunakan. Faktor-faktor seperti alokasi memori berbasis halaman, lokalitas, penembolokan, dan padding. Selain itu, beberapa versi baris yang memiliki transaksi aktif yang terkait atau yang menunggu pengumpulan sampah.

    • Ukuran minimum yang diperlukan untuk data dan indeks dalam tabel diberikan oleh perhitungan untuk <table size>, dibahas nanti dalam artikel ini.

    • Menghitung penggunaan memori adalah perkiraan terbaik dan Anda disarankan untuk menyertakan perencanaan kapasitas dalam rencana penyebaran Anda.

  • Ukuran data baris, dan apakah sesuai dengan batasan ukuran baris 8.060 byte? Untuk menjawab pertanyaan-pertanyaan ini, gunakan komputasi untuk <row body size>, yang dibahas nanti dalam artikel ini.

Tabel yang dioptimalkan memori terdiri dari kumpulan baris dan indeks yang berisi penunjuk ke baris. Gambar berikut mengilustrasikan tabel dengan indeks dan baris, yang pada gilirannya memiliki header dan badan baris:

Diagram tabel memori yang dioptimalkan.

Ukuran tabel komputasi

Ukuran dalam memori tabel, dalam byte, dihitung sebagai berikut:

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

Ukuran indeks hash diperbaiki pada waktu pembuatan tabel dan tergantung pada jumlah wadah aktual. bucket_count Ditentukan dengan definisi indeks dibulatkan ke atas ke daya terdekat 2 untuk mendapatkan jumlah wadah aktual. Misalnya, jika yang ditentukan bucket_count adalah 100000, jumlah wadah aktual untuk indeks 131072.

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

Ukuran indeks non-kluster berada dalam urutan <row count> * <index key size>.

Ukuran baris dihitung dengan menambahkan header dan isi:

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

Menghitung ukuran isi baris

Baris dalam tabel yang dioptimalkan memori memiliki komponen berikut:

  • Header baris berisi tanda waktu yang diperlukan untuk menerapkan penerapan versi baris. Header baris juga berisi penunjuk indeks untuk mengimplementasikan rantai baris dalam wadah hash (dijelaskan sebelumnya).

  • Isi baris berisi data kolom aktual, yang mencakup beberapa informasi tambahan seperti array null untuk kolom yang dapat diubah ke null dan array offset untuk jenis data dengan panjang variabel.

Gambar berikut mengilustrasikan struktur baris untuk tabel yang memiliki dua indeks:

Diagram struktur baris untuk tabel yang memiliki dua indeks.

Tanda waktu mulai dan berakhir menunjukkan periode di mana versi baris tertentu valid. Transaksi yang dimulai dalam interval ini dapat melihat versi baris ini. Untuk informasi selengkapnya, lihat Transaksi dengan Tabel yang Dioptimalkan Memori.

Penunjuk indeks menunjuk ke baris berikutnya dalam rantai milik wadah hash. Gambar berikut mengilustrasikan struktur tabel dengan dua kolom (nama, kota), dan dengan dua indeks, satu pada nama kolom, dan satu di kota kolom.

Diagram struktur tabel dengan dua kolom dan indeks.

Dalam angka ini, nama-nama John dan Jane di-hash ke wadah pertama. Susan di-hash ke wadah kedua. Kota-kota Beijing dan Bogota di-hash ke wadah pertama. Paris dan Prague di-hash ke wadah kedua.

Dengan demikian, rantai untuk indeks hash pada nama adalah sebagai berikut:

  • Wadah pertama: (John, Beijing); ; (John, Paris)(Jane, Prague)
  • Wadah kedua: (Susan, Bogota)

Rantai untuk indeks di kota adalah sebagai berikut:

  • Wadah pertama: (John, Beijing), (Susan, Bogota)
  • Wadah kedua: (John, Paris), (Jane, Prague)

Tanda waktu akhir ∞ (tak terbatas) menunjukkan bahwa ini adalah versi baris yang saat ini valid. Baris tidak diperbarui atau dihapus sejak versi baris ini ditulis.

Untuk waktu yang lebih besar dari 200, tabel berisi baris berikut:

Nama Kota
John Beijing
Jane Praha

Namun, setiap transaksi aktif dengan waktu 100mulai , lihat versi tabel berikut:

Nama Kota
John Paris
Jane Praha
Susan Bogota

Perhitungan <row body size> dibahas dalam tabel berikut.

Ada dua komputasi berbeda untuk ukuran isi baris: ukuran komputasi dan ukuran aktual:

  • Ukuran komputasi, yang ditandai dengan ukuran isi baris komputasi, digunakan untuk menentukan apakah batasan ukuran baris 8.060 byte terlampaui.

  • Ukuran aktual, yang ditandai dengan ukuran isi baris aktual, adalah ukuran penyimpanan aktual dari isi baris dalam memori dan dalam file titik pemeriksaan.

Ukuran isi baris komputasi dan ukuran isi baris aktual dihitung sama. Satu-satunya perbedaan adalah perhitungan ukuran kolom (n)varchar(i) dan varbinary(i), seperti yang tercermin di bagian bawah tabel berikut. Ukuran isi baris komputasi menggunakan ukuran i yang dideklarasikan sebagai ukuran kolom, sementara ukuran isi baris aktual menggunakan ukuran data yang sebenarnya.

Tabel berikut ini menjelaskan perhitungan ukuran isi baris, yang diberikan sebagai <actual row body size> = SUM(<size of shallow types>) + 2 + 2 * <number of deep type columns>.

Bagian Ukuran Komentar
Kolom jenis dangkal SUM(<size of shallow types>). Ukuran dalam byte dari jenis individu adalah sebagai berikut:

bit: 1
kecil:1
smallint: 2
int: 4
nyata: 4
smalldatetime: 4
smallmoney: 4
bigint: 8
tanggalwaktu: 8
datetime2: 8
float: 8
uang: 8
numerik (presisi <= 18): 8
waktu: 8
numerik(presisi > 18): 16
pengidentifikasi unik: 16
Padding kolom dangkal Kemungkinan nilai adalah:

1 jika ada kolom jenis dalam dan ukuran data total kolom dangkal adalah sebagai angka ganjil.

0 Sebaliknya
Jenis mendalam adalah jenis (var)biner dan (n)(var)char.
Array offset untuk kolom tipe dalam Kemungkinan nilai adalah:

0 jika tidak ada kolom tipe dalam

2 + 2 * <number of deep type columns> Sebaliknya
Jenis mendalam adalah jenis (var)biner dan (n)(var)char.
Array null <number of nullable columns> / 8 dibulatkan ke atas hingga byte penuh. Array memiliki 1 bit per kolom nullable. Ini dibulatkan ke byte penuh.
Padding array null Kemungkinan nilai adalah:

1 jika ada kolom tipe dalam, dan ukuran NULL array adalah jumlah byte ganjil.
0 Sebaliknya
Jenis mendalam adalah jenis (var)biner dan (n)(var)char.
Padding Jika tidak ada kolom jenis dalam: 0

Jika ada kolom jenis dalam, 0 - 7 byte padding ditambahkan, berdasarkan perataan terbesar yang diperlukan oleh kolom dangkal. Setiap kolom dangkal memerlukan perataan yang sama dengan ukurannya seperti yang didokumentasikan sebelumnya, kecuali bahwa kolom GUID membutuhkan perataan 1 byte (bukan 16) dan kolom numerik selalu memerlukan perataan 8 byte (tidak pernah 16). Persyaratan perataan terbesar di antara semua kolom dangkal digunakan. 0 - 7 byte padding ditambahkan singgah sehingga ukuran total sejauh ini (tanpa kolom jenis dalam) adalah kelipatan dari perataan yang diperlukan.
Jenis mendalam adalah jenis (var)biner dan (n)(var)char.
Kolom tipe dalam panjang tetap SUM(<size of fixed length deep type columns>)

Ukuran setiap kolom adalah sebagai berikut:

i untuk char(i) dan biner(i).
2 * i untuk nchar(i)
Kolom tipe dalam dengan panjang tetap adalah kolom tipe karakter(i), nchar(i), atau biner(i).
Ukuran komputasi kolom tipe dalam panjang variabel SUM(<computed size of variable length deep type columns>)

Ukuran komputasi setiap kolom adalah sebagai berikut:

i untuk varchar(i) dan varbinary(i)

2 * i untuk nvarchar(i)
Baris ini hanya diterapkan ke ukuran isi baris komputasi.

Kolom tipe dalam panjang variabel adalah kolom jenis varchar(i), nvarchar(i), atau varbinary(i). Ukuran komputasi ditentukan oleh panjang maksimum (i) kolom.
Ukuran aktual kolom tipe dalam panjang variabel SUM(<actual size of variable length deep type columns>)

Ukuran aktual setiap kolom adalah sebagai berikut:

n, di mana n adalah jumlah karakter yang disimpan dalam kolom, untuk varchar(i).

2 * n, di mana n adalah jumlah karakter yang disimpan dalam kolom, untuk nvarchar(i).

n, di mana n adalah jumlah byte yang disimpan dalam kolom, untuk varbinary(i).
Baris ini hanya diterapkan ke ukuran isi baris aktual.

Ukuran aktual ditentukan oleh data yang disimpan dalam kolom dalam baris.

Contoh: Komputasi ukuran tabel dan baris

Untuk indeks hash, jumlah wadah aktual dibulatkan ke atas ke daya terdekat 2. Misalnya, jika yang ditentukan bucket_count adalah 100000, jumlah wadah aktual untuk indeks 131072.

Pertimbangkan tabel Pesanan dengan definisi berikut:

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

Tabel ini memiliki satu indeks hash dan indeks non-kluster (kunci primer). Ini juga memiliki tiga kolom panjang tetap dan satu kolom panjang variabel, dengan salah satu kolom yang NULLdapat (OrderDescription). Mari kita asumsikan Orders tabel memiliki 8.379 baris, dan panjang rata-rata nilai dalam OrderDescription kolom adalah 78 karakter.

Untuk menentukan ukuran tabel, pertama-tama tentukan ukuran indeks. bucket_count untuk kedua indeks ditentukan sebagai 10000. Ini dibulatkan ke atas ke daya terdekat 2: 16384. Oleh karena itu, ukuran total indeks untuk Orders tabel adalah:

8 * 16384 = 131072 bytes

Yang tersisa adalah ukuran data tabel, yaitu:

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

(Contoh tabel memiliki 8.379 baris.) Sekarang, kita memiliki:

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

Selanjutnya, mari kita hitung <actual row body size>:

  • Kolom jenis dangkal:

    SUM(<size of shallow types>) = 4 <int> + 4 <int> + 8 <datetime> = 16
    
  • Padding kolom dangkal adalah 0, karena ukuran kolom dangkal total genap.

  • Array offset untuk kolom tipe dalam:

    2 + 2 * <number of deep type columns> = 2 + 2 * 1 = 4
    
  • NULL array = 1

  • NULL array padding = 1, karena NULL ukuran array ganjil dan ada kolom tipe dalam.

  • Padding

    • 8 adalah persyaratan penyelarasan terbesar
    • Ukuran sejauh ini adalah 16 + 0 + 4 + 1 + 1 = 22
    • Kelipatan terdekat dari 8 adalah 24
    • Total padding adalah 24 - 22 = 2 byte
  • Tidak ada kolom tipe dalam panjang tetap (kolom tipe dalam panjang tetap: 0.).

  • Ukuran sebenarnya dari kolom tipe dalam adalah 2 * 78 = 156. Kolom OrderDescription tipe dalam tunggal memiliki jenis nvarchar.

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

Untuk menyelesaikan penghitungan:

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

Total ukuran tabel dalam memori dengan demikian sekitar 2 megabyte. Ini tidak memperhitungkan potensi overhead yang dikeluarkan oleh alokasi memori, dan penerapan versi baris apa pun yang diperlukan untuk transaksi yang mengakses tabel ini.

Memori aktual yang dialokasikan untuk dan digunakan oleh tabel ini dan indeksnya dapat diperoleh melalui kueri berikut:

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

Batasan kolom di luar baris

Batasan dan peringatan tertentu untuk menggunakan kolom di luar baris dalam tabel yang dioptimalkan memori tercantum sebagai berikut:

  • Jika ada indeks penyimpan kolom pada tabel yang dioptimalkan memori, maka semua kolom harus pas berturut-turut.
  • Semua kolom kunci indeks harus disimpan secara berurut. Jika kolom kunci indeks tidak pas berbaris, penambahan indeks gagal.
  • Peringatan tentang mengubah tabel yang dioptimalkan memori dengan kolom di luar baris.
  • Untuk LOB, batasan ukuran mencerminkan tabel berbasis disk (batas 2 GB pada nilai LOB).
  • Untuk performa optimal, sebaiknya sebagian besar kolom harus pas dalam 8.060 byte.
  • Data di luar baris dapat menyebabkan penggunaan memori dan/atau disk yang berlebihan.