Saya tidak dapat mengatakan dengan tepat mengapa perilaku ini terjadi tetapi saya percaya saya telah mengembangkan model perilaku yang baik melalui pengujian brute force. Kesimpulan berikut hanya berlaku saat memuat data ke dalam satu kolom dan dengan bilangan bulat yang didistribusikan dengan sangat baik.
Pertama saya mencoba memvariasikan jumlah baris yang dimasukkan ke dalam CCI menggunakan TOP
. Saya menggunakan ID % 16000
semua tes. Di bawah ini adalah grafik yang membandingkan baris yang dimasukkan ke ukuran segmen grup baris terkompresi:
Di bawah ini adalah grafik baris yang dimasukkan ke waktu CPU dalam ms. Perhatikan bahwa sumbu X memiliki titik awal yang berbeda:
Kita dapat melihat bahwa ukuran segmen rowgroup tumbuh pada tingkat linier dan menggunakan sejumlah kecil CPU hingga sekitar 1 M baris. Pada saat itu ukuran grup baris menurun secara dramatis dan penggunaan CPU meningkat secara dramatis. Tampaknya kita membayar mahal pada CPU untuk kompresi itu.
Ketika memasukkan kurang dari 1024000 baris saya berakhir dengan grup baris terbuka di CCI. Namun, memaksa kompresi menggunakan REORGANIZE
atau REBUILD
tidak berpengaruh pada ukuran. Sebagai tambahan, saya menemukan hal menarik bahwa ketika saya menggunakan variabel untuk TOP
saya berakhir dengan rowgroup terbuka tetapi dengan RECOMPILE
saya berakhir dengan rowgroup tertutup.
Selanjutnya saya diuji dengan memvariasikan nilai modulus sambil menjaga jumlah baris yang sama. Berikut adalah contoh data saat memasukkan 102400 baris:
╔═══════════╦═════════╦═══════════════╦═════════════╗
║ TOP_VALUE ║ MOD_NUM ║ SIZE_IN_BYTES ║ CPU_TIME_MS ║
╠═══════════╬═════════╬═══════════════╬═════════════╣
║ 102400 ║ 1580 ║ 13504 ║ 352 ║
║ 102400 ║ 1590 ║ 13584 ║ 316 ║
║ 102400 ║ 1600 ║ 13664 ║ 317 ║
║ 102400 ║ 1601 ║ 19624 ║ 270 ║
║ 102400 ║ 1602 ║ 25568 ║ 283 ║
║ 102400 ║ 1603 ║ 31520 ║ 286 ║
║ 102400 ║ 1604 ║ 37464 ║ 288 ║
║ 102400 ║ 1605 ║ 43408 ║ 273 ║
║ 102400 ║ 1606 ║ 49360 ║ 269 ║
║ 102400 ║ 1607 ║ 55304 ║ 265 ║
║ 102400 ║ 1608 ║ 61256 ║ 262 ║
║ 102400 ║ 1609 ║ 67200 ║ 255 ║
║ 102400 ║ 1610 ║ 73144 ║ 265 ║
║ 102400 ║ 1620 ║ 132616 ║ 132 ║
║ 102400 ║ 1621 ║ 138568 ║ 100 ║
║ 102400 ║ 1622 ║ 144512 ║ 91 ║
║ 102400 ║ 1623 ║ 150464 ║ 75 ║
║ 102400 ║ 1624 ║ 156408 ║ 60 ║
║ 102400 ║ 1625 ║ 162352 ║ 47 ║
║ 102400 ║ 1626 ║ 164712 ║ 41 ║
╚═══════════╩═════════╩═══════════════╩═════════════╝
Hingga nilai mod 1600 ukuran segmen baris meningkat secara linear sebesar 80 byte untuk setiap tambahan 10 nilai unik. Ini adalah kebetulan yang menarik bahwa secara BIGINT
tradisional memakan 8 byte dan ukuran segmen meningkat 8 byte untuk setiap nilai unik tambahan. Melewati nilai mod 1600 ukuran segmen meningkat dengan cepat sampai stabil.
Juga membantu untuk melihat data ketika meninggalkan nilai modulus yang sama dan mengubah jumlah baris yang dimasukkan:
╔═══════════╦═════════╦═══════════════╦═════════════╗
║ TOP_VALUE ║ MOD_NUM ║ SIZE_IN_BYTES ║ CPU_TIME_MS ║
╠═══════════╬═════════╬═══════════════╬═════════════╣
║ 300000 ║ 5000 ║ 600656 ║ 131 ║
║ 305000 ║ 5000 ║ 610664 ║ 124 ║
║ 310000 ║ 5000 ║ 620672 ║ 127 ║
║ 315000 ║ 5000 ║ 630680 ║ 132 ║
║ 320000 ║ 5000 ║ 40688 ║ 2344 ║
║ 325000 ║ 5000 ║ 40696 ║ 2577 ║
║ 330000 ║ 5000 ║ 40704 ║ 2589 ║
║ 335000 ║ 5000 ║ 40712 ║ 2673 ║
║ 340000 ║ 5000 ║ 40728 ║ 2715 ║
║ 345000 ║ 5000 ║ 40736 ║ 2744 ║
║ 350000 ║ 5000 ║ 40744 ║ 2157 ║
╚═══════════╩═════════╩═══════════════╩═════════════╝
Sepertinya ketika jumlah baris yang dimasukkan <~ 64 * jumlah nilai unik yang kita lihat kompresi relatif buruk (2 byte per baris untuk mod <= 65000) dan rendah, penggunaan CPU linier. Ketika jumlah baris yang dimasukkan> ~ 64 * jumlah nilai unik kita melihat kompresi yang lebih baik dan lebih tinggi, penggunaan CPU masih linier. Ada transisi antara dua kondisi yang tidak mudah bagi saya untuk membuat model tetapi dapat dilihat pada grafik. Tampaknya tidak benar bahwa kita melihat penggunaan CPU maksimum saat memasukkan 64 baris persis untuk setiap nilai unik. Sebaliknya, kami hanya dapat memasukkan maksimum 1048576 baris ke dalam grup baris dan kami melihat penggunaan dan kompresi CPU jauh lebih tinggi begitu ada lebih dari 64 baris per nilai unik.
Di bawah ini adalah plot kontur tentang bagaimana waktu cpu berubah ketika jumlah baris yang disisipkan dan jumlah baris unik berubah. Kita bisa melihat pola yang dijelaskan di atas:
Di bawah ini adalah plot kontur ruang yang digunakan oleh segmen tersebut. Setelah titik tertentu kita mulai melihat kompresi yang jauh lebih baik, seperti dijelaskan di atas:
Sepertinya setidaknya ada dua algoritma kompresi yang berbeda yang bekerja di sini. Mengingat hal di atas, masuk akal bahwa kita akan melihat penggunaan CPU maksimum saat memasukkan 1048576 baris. Juga masuk akal bahwa kita melihat penggunaan CPU paling banyak pada saat itu ketika memasukkan sekitar 16000 baris. 1048576/64 = 16384.
Saya mengunggah semua data mentah saya di sini kalau-kalau ada yang ingin menganalisisnya.
Layak disebutkan apa yang terjadi dengan rencana paralel. Saya hanya mengamati perilaku ini dengan nilai yang didistribusikan secara merata. Saat melakukan insert paralel, seringkali ada elemen keacakan dan untaian biasanya tidak seimbang.
Letakkan 2097152 baris di tabel pementasan:
DROP TABLE IF EXISTS STG_2097152;
CREATE TABLE dbo.STG_2097152 (ID BIGINT NOT NULL);
INSERT INTO dbo.STG_2097152 WITH (TABLOCK)
SELECT TOP (2097152) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
Sisipan ini selesai dalam waktu kurang dari satu detik dan memiliki kompresi yang buruk:
DROP TABLE IF EXISTS dbo.CCI_BIGINT;
CREATE TABLE dbo.CCI_BIGINT (ID BIGINT NOT NULL, INDEX CCI CLUSTERED COLUMNSTORE);
INSERT INTO dbo.CCI_BIGINT WITH (TABLOCK)
SELECT ID % 16000
FROM dbo.STG_2097152
OPTION (MAXDOP 2);
Kita dapat melihat efek dari utas yang tidak seimbang:
╔════════════╦════════════╦══════════════╦═══════════════╗
║ state_desc ║ total_rows ║ deleted_rows ║ size_in_bytes ║
╠════════════╬════════════╬══════════════╬═══════════════╣
║ OPEN ║ 13540 ║ 0 ║ 311296 ║
║ COMPRESSED ║ 1048576 ║ 0 ║ 2095872 ║
║ COMPRESSED ║ 1035036 ║ 0 ║ 2070784 ║
╚════════════╩════════════╩══════════════╩═══════════════╝
Ada berbagai trik yang dapat kita lakukan untuk memaksa agar benang seimbang dan memiliki distribusi baris yang sama. Ini salah satunya:
DROP TABLE IF EXISTS dbo.CCI_BIGINT;
CREATE TABLE dbo.CCI_BIGINT (ID BIGINT NOT NULL, INDEX CCI CLUSTERED COLUMNSTORE);
INSERT INTO dbo.CCI_BIGINT WITH (TABLOCK)
SELECT FLOOR(0.5 * ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) % 15999
FROM dbo.STG_2097152
OPTION (MAXDOP 2)
Memilih bilangan ganjil untuk modulus penting di sini. SQL Server memindai tabel pementasan secara serial, menghitung nomor baris, kemudian menggunakan distribusi round robin untuk meletakkan baris pada utas paralel. Itu berarti bahwa kita akan berakhir dengan utas yang seimbang sempurna.
Sisipan membutuhkan waktu sekitar 40 detik yang mirip dengan penyisipan serial. Kami mendapat grup baris terkompresi dengan baik:
╔════════════╦════════════╦══════════════╦═══════════════╗
║ state_desc ║ total_rows ║ deleted_rows ║ size_in_bytes ║
╠════════════╬════════════╬══════════════╬═══════════════╣
║ COMPRESSED ║ 1048576 ║ 0 ║ 128568 ║
║ COMPRESSED ║ 1048576 ║ 0 ║ 128568 ║
╚════════════╩════════════╩══════════════╩═══════════════╝
Kita bisa mendapatkan hasil yang sama dengan memasukkan data dari tabel pementasan asli:
DROP TABLE IF EXISTS dbo.CCI_BIGINT;
CREATE TABLE dbo.CCI_BIGINT (ID BIGINT NOT NULL, INDEX CCI CLUSTERED COLUMNSTORE);
INSERT INTO dbo.CCI_BIGINT WITH (TABLOCK)
SELECT t.ID % 16000 ID
FROM (
SELECT TOP (2) ID
FROM (SELECT 1 ID UNION ALL SELECT 2 ) r
) s
CROSS JOIN dbo.STG_1048576 t
OPTION (MAXDOP 2, NO_PERFORMANCE_SPOOL);
Di sini distribusi round robin digunakan untuk tabel turunan s
sehingga satu pemindaian tabel dilakukan pada setiap thread paralel:
Kesimpulannya, saat memasukkan bilangan bulat yang terdistribusi secara merata Anda dapat melihat kompresi yang sangat tinggi ketika setiap bilangan bulat unik muncul lebih dari 64 kali. Ini mungkin karena algoritma kompresi yang digunakan berbeda. Mungkin ada biaya tinggi dalam CPU untuk mencapai kompresi ini. Perubahan kecil dalam data dapat menyebabkan perbedaan dramatis dalam ukuran segmen rowgroup terkompresi. Saya menduga bahwa melihat kasus terburuk (dari perspektif CPU) akan jarang terjadi, setidaknya untuk kumpulan data ini. Bahkan lebih sulit untuk dilihat saat melakukan sisipan paralel.