Berapakah biaya baris saat menggunakan Kompresi Halaman?

10

Saya telah membuat tabel dengan 650 Numeric (19,4) kolom. Ketika saya mengaktifkan Page Compression, dengan menjalankan

ALTER TABLE fct.MyTable REBUILD  WITH (DATA_COMPRESSION = PAGE);

saya mendapat

Msg 1975, Level 16, State 1
Indeks 'PK_Mytable' panjang baris melebihi panjang maksimum yang diijinkan dari '8060' byte.

tetapi 650 kali 9 byte hanya 5850 byte, yang cukup jauh dari batas yang dinyatakan 8060 byte.

Server menjalankan Windows 2012 r2 dengan SQL Server 2016 SP1 CU2

Berapakah biaya baris saat menggunakan Kompresi Halaman?

Berikut ini beberapa kode untuk menunjukkan apa yang saya maksud:

/* test script to demo MSG 1975 */
DECLARE @sql NVARCHAR(max)='', @i INT =0
drop table if exists dbo.mytable;

SET @sql = 'Create table dbo.Mytable (MyTableID bigint not null 
  identity(1,1) primary key clustered, '

WHILE @i < 593 BEGIN
    SET @sql += ' Column' + LTRIM(@i) + ' numeric(19,4) null, '
    SET @i +=1
END

SET @sql += ' LastColumn int) '
--SET @sql += ' with (DATA_COMPRESSION = ROW) '
SET @sql += ' with (DATA_COMPRESSION = PAGE) '

SELECT @sql
EXEC sys.sp_executesql @sql

SELECT top 10000 * FROM dbo.MyTable MT

Kompresi baris juga gagal, tetapi pada jumlah baris yang berbeda.

Henrik Staun Poulsen
sumber
Seberapa besar kunci utama Anda? Jika ini adalah tabel fakta dan Anda ingin mengompresi dan meningkatkan kinerja, saya sarankan Anda membaca di indeks kolom toko, mereka dapat membuat dampak yang cukup. Overhead kompresi halaman lebih banyak menggunakan cpu untuk melakukan dekompresi.
Stijn Wynants
@StijnWynants; 8 byte digunakan untuk BigInts. Ini memang fakta, tetapi tidak ada cukup baris masuk untuk menjamin indeks kolom toko.
Henrik Staun Poulsen

Jawaban:

13

Jika Anda mencoba membuat tabel Anda tanpa Kendala PK berkerumun, dan Anda akan mendapatkan kesalahan yang sedikit berbeda:

Msg 1701, Level 16, State 1, Line 1 Membuat atau mengubah tabel 'Mytable' gagal karena ukuran baris minimum adalah 8067, termasuk 1530 byte overhead internal. Ini melebihi ukuran baris tabel maksimum yang diijinkan yaitu 8060 byte.

Dalam pesan kesalahan ini, Anda dapat melihat bahwa ada 1530 byte overhead internal untuk kompresi halaman.

Sekarang, Anda dapat melakukan perhitungan:

  • 8 byte untuk bigintMyTableID
  • 4 byte untuk intKolom Terakhir
  • 9 byte untuk masing-masing 593 numeric(19,4)kolom (total 5337 byte)
  • 1530 byte kompresi overhead

Jadi, 8 + 4 + (593 * 9) + 1530 = 6879. Tunggu sebentar .... Itu masih di bawah 8060. Ada apa dengan itu ?!


Algoritma Kompresi Halaman sebenarnya menumpuk beberapa algoritma kompresi bersama. Langkah pertama adalah menerapkan kompresi ROW. Overhead kompresi baris tidak termasuk dalam 1530 byte overhead yang tercantum dalam pesan kesalahan itu.

Anda dapat membaca lebih lanjut tentang cara kompresi baris bekerja di sini di blog saya dan di sini di BOL . Anda akan mencatat di artikel BOL yang menggambarkan numericpenyimpanan sebagai "Penyimpanan ini persis sama dengan format penyimpanan vardecimal," tetapi tidak menjelaskan vardecimal. Posting ini mencakup vardecimalsedikit lebih banyak - pada dasarnya, ia menambahkan 2 byte overhead per kolom untuk menyimpan panjang sebenarnya (mirip dengan apa yang varchardilakukan).

Kompresi baris akan membutuhkan tambahan 2 byte untuk masing-masing dari 593 numerickolom, ditambah bigintdan intakan membutuhkan 1 byte masing-masing overhead.

The baris-dikompresi persyaratan penyimpanan akan menjadi:

  • 8 byte + 1 byte overhead untuk bigintMyTableID
  • 4 byte + 1 byte overhead untuk intLastColumn
  • 9 byte + 2 byte overhead untuk masing-masing 593 numeric(19,4)kolom
  • 1188 byte overhead kompresi ROW

8 + 4 + (593 * 9) = 5349 byte data

1 + 1 + (593 * 2) = 1188 byte kompresi baris atas

Total 6537 byte untuk skema kompresi baris


Sekarang kita memiliki ukuran baris untuk skema terkompresi baris, kita dapat meninjau kembali matematika kita. Ukuran baris yang dikompresi halaman akan menjadi ukuran data + overhead kompresi baris + overhead kompresi halaman:

  • 8 byte untuk bigintMyTableID
  • 4 byte untuk intKolom Terakhir
  • 9 byte untuk masing-masing 593 numeric(19,4)kolom
  • 1188 byte overhead kompresi ROW
  • 1530 byte overhead kompresi PAGE
  5349 byte data 
+ 1188 byte kompresi baris atas 
+1530 ​​byte kompresi overhead halaman 

Total 8067 byte

AMtwo
sumber
1
Saya suka kesimpulan Anda: "Dalam kebanyakan kasus, Anda akan menemukan bahwa kompresi baris dapat menghemat ruang - tetapi tidak selalu." 2718 byte overhead jauh lebih banyak dari yang saya harapkan. Terima kasih banyak telah meluangkan waktu untuk menulis jawaban yang begitu terperinci.
Henrik Staun Poulsen
1
@HenrikStaunPoulsen Satu hal penting tambahan yang perlu diingat adalah bahwa SQL Server perlu berasumsi bahwa data Anda mungkin tidak dapat dikompresi. Jadi, bahkan jika data Anda akan dikompres hingga kurang dari 8060 byte, SQL Server harus membuat perhitungan ukuran baris berdasarkan ukuran baris maksimum teoritis untuk data yang tidak dapat dikompres.
AMtwo
Setelah 3 hari, saya masih kagum dengan jumlah byte yang diperlukan untuk kompresi Row; 2 byte per kolom. Kompresi Halaman menambahkan hampir 3 byte di atasnya. Tapi; Terima kasih untuk bantuannya. Itu paling bermanfaat.
Henrik Staun Poulsen