Bagikan melalui


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 di luar baris memiliki tabel internal yang sesuai, yang pada gilirannya memiliki satu indeks non-klaster. 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 masing-masing memiliki header dan badan baris.

Diagram tabel memori yang dioptimalkan.

Hitung ukuran tabel

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 tetap pada waktu pembuatan tabel dan tergantung pada jumlah wadah sebenarnya. bucket_count yang ditentukan dengan definisi indeks dibulatkan ke atas ke bilangan pangkat terdekat dari 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 versi baris. Header baris juga berisi penunjuk indeks untuk mengimplementasikan rantai baris dalam wadah hash (dijelaskan sebelumnya).

  • Isi baris berisi data kolom yang sebenarnya, yang mencakup beberapa informasi tambahan seperti array null untuk kolom yang bisa 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 mengarahkan ke baris selanjutnya dalam rantai yang termasuk dalam keranjang 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 gambar ini, nama-nama John dan Jane dihash 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 indeks 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 mulai 100, lihat versi tabel yang 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.

Baik ukuran isi baris yang dihitung maupun ukuran isi baris yang aktual dihitung dengan cara yang 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 tipe dangkal SUM(<size of shallow types>). Ukuran dalam byte dari masing-masing tipe 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 tipe mendalam dan ukuran total data dari kolom dangkal merupakan bilangan 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 mendalam

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 menjadi byte penuh. Array memiliki 1 bit per kolom yang dapat bernilai null. Ini dibulatkan ke byte penuh.
Pengisian null untuk array Kemungkinan nilai adalah:

1 jika ada kolom bertipe dalam, dan ukuran NULL array merupakan jumlah byte ganjil.
0 Sebaliknya
Jenis mendalam adalah jenis (var)biner dan (n)(var)char.
Padding Jika tidak ada kolom tipe mendalam: 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 sedemikian rupa sehingga ukuran total sejauh ini (tanpa kolom tipe dalam) adalah kelipatan dari penyelarasan yang dibutuhkan.
Jenis mendalam adalah jenis (var)biner dan (n)(var)char.
Kolom jenis mendalam dengan 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).
Kolom tipe dalam dengan panjang variabel ukuran komputasi 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 badan baris terhitung.

Kolom tipe dalam panjang variabel adalah kolom jenis varchar(i), nvarchar(i), atau varbinary(i). Ukuran komputasi ditentukan oleh panjang maksimum (i) kolom.
Kolom tipe dalam panjang variabel ukuran aktual 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 berlaku untuk ukuran badan isi baris yang sebenarnya.

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

Contoh: Komputasi ukuran tabel dan baris

Untuk indeks hash, jumlah bucket aktual dibulatkan ke atas ke pangkat terdekat dari 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 dapat diubah ke null (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>:

  • Jenis kolom dangkal:

    SUM(<size of shallow types>) = 4 <int> + 4 <int> + 8 <datetime> = 16
    
  • Padding kolom dangkal adalah 0, karena ukuran total kolom dangkal adalah 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.

  • Pengisi

    • 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 mendalam dengan panjang tetap (Kolom tipe mendalam dengan panjang tetap: 0.).

  • Ukuran sebenarnya dari kolom tipe dalam adalah 2 * 78 = 156. Kolom tipe yang dalam tunggal OrderDescription 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 terjadi akibat alokasi memori, dan 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 untuk 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 kolom pada tabel yang dioptimalkan memori, maka semua kolom harus pas di baris.
  • Semua kolom kunci indeks harus disimpan secara berurut. Jika kolom kunci indeks tidak pas berbaris, penambahan indeks gagal.
  • Peringatan tentang mengubah tabel yang dioptimalkan untuk memori dengan kolom di luar baris standar.
  • 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.