Jarang
Ketika melakukan beberapa tes pada kolom yang jarang, seperti yang Anda lakukan, ada kemunduran kinerja yang ingin saya ketahui penyebab langsungnya.
DDL
Saya membuat dua tabel identik, satu dengan 4 kolom jarang dan satu tanpa kolom jarang.
--Non Sparse columns table & NC index
CREATE TABLE dbo.nonsparse( ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
charval char(20) NULL,
varcharval varchar(20) NULL,
intval int NULL,
bigintval bigint NULL
);
CREATE INDEX IX_Nonsparse_intval_varcharval
ON dbo.nonsparse(intval,varcharval)
INCLUDE(bigintval,charval);
-- sparse columns table & NC index
CREATE TABLE dbo.sparse( ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
charval char(20) SPARSE NULL ,
varcharval varchar(20) SPARSE NULL,
intval int SPARSE NULL,
bigintval bigint SPARSE NULL
);
CREATE INDEX IX_sparse_intval_varcharval
ON dbo.sparse(intval,varcharval)
INCLUDE(bigintval,charval);
DML
Saya kemudian memasukkan sekitar 2.540 nilai NON-NULL ke dalam keduanya.
INSERT INTO dbo.nonsparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT 'Val1','Val2',20,19
FROM MASTER..spt_values;
INSERT INTO dbo.sparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT 'Val1','Val2',20,19
FROM MASTER..spt_values;
Setelah itu, saya memasukkan nilai NULL 1M ke dalam kedua tabel
INSERT INTO dbo.nonsparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT TOP(1000000) NULL,NULL,NULL,NULL
FROM MASTER..spt_values spt1
CROSS APPLY MASTER..spt_values spt2;
INSERT INTO dbo.sparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT TOP(1000000) NULL,NULL,NULL,NULL
FROM MASTER..spt_values spt1
CROSS APPLY MASTER..spt_values spt2;
Pertanyaan
Eksekusi tabel nonsparse
Saat menjalankan kueri ini dua kali pada tabel nonsparse yang baru dibuat:
SET STATISTICS IO, TIME ON;
SELECT * FROM dbo.nonsparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
Bacaan logis menunjukkan 5257 halaman
(1002540 rows affected)
Table 'nonsparse'. Scan count 1, logical reads 5257, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Dan waktu cpu adalah pada 343 ms
SQL Server Execution Times:
CPU time = 343 ms, elapsed time = 3850 ms.
eksekusi tabel jarang
Menjalankan kueri yang sama dua kali di tabel jarang:
SELECT * FROM dbo.sparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
Bacaan lebih rendah, 1763
(1002540 rows affected)
Table 'sparse'. Scan count 1, logical reads 1763, physical reads 3, read-ahead reads 1759, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Tetapi waktu cpu lebih tinggi, 547 ms .
SQL Server Execution Times:
CPU time = 547 ms, elapsed time = 2406 ms.
Rencana pelaksanaan tabel jarang
rencana eksekusi tabel tidak jarang
Pertanyaan
Pertanyaan asli
Karena nilai NULL tidak disimpan secara langsung di kolom jarang, dapatkah peningkatan waktu cpu disebabkan oleh mengembalikan nilai NULL sebagai resultset? Atau apakah itu hanya perilaku sebagaimana dicatat dalam dokumentasi ?
Kolom jarang mengurangi persyaratan ruang untuk nilai nol dengan biaya lebih banyak overhead untuk mengambil nilai nonnull
Atau apakah overhead hanya terkait dengan pembacaan & penyimpanan yang digunakan?
Bahkan ketika menjalankan ssms dengan hasil buangan setelah opsi eksekusi, waktu cpu dari sparse select lebih tinggi (407 ms) dibandingkan dengan non sparse (219 ms).
EDIT
Ini mungkin merupakan overhead dari nilai-nilai non null, bahkan jika hanya ada 2.540, tetapi saya masih tidak yakin.
Ini tampaknya tentang kinerja yang sama, tetapi faktor jarang hilang.
CREATE INDEX IX_Filtered
ON dbo.sparse(charval,varcharval,intval,bigintval)
WHERE charval IS NULL
AND varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL;
CREATE INDEX IX_Filtered
ON dbo.nonsparse(charval,varcharval,intval,bigintval)
WHERE charval IS NULL
AND varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL;
SET STATISTICS IO, TIME ON;
SELECT charval,varcharval,intval,bigintval FROM dbo.sparse WITH(INDEX(IX_Filtered))
WHERE charval IS NULL AND varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL
OPTION(RECOMPILE,MAXDOP 1);
SELECT charval,varcharval,intval,bigintval
FROM dbo.nonsparse WITH(INDEX(IX_Filtered))
WHERE charval IS NULL AND
varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL
OPTION(RECOMPILE,MAXDOP 1);
Tampaknya memiliki waktu eksekusi yang sama:
SQL Server Execution Times:
CPU time = 297 ms, elapsed time = 292 ms.
SQL Server Execution Times:
CPU time = 281 ms, elapsed time = 319 ms.
Tetapi mengapa logika membaca jumlah yang sama sekarang? Bukankah seharusnya indeks yang difilter untuk kolom jarang tidak menyimpan apa pun kecuali bidang ID yang disertakan dan beberapa halaman non-data lainnya?
Table 'sparse'. Scan count 1, logical reads 5785,
Table 'nonsparse'. Scan count 1, logical reads 5785
Dan ukuran kedua indeks:
RowCounts Used_MB Unused_MB Total_MB
1000000 45.20 0.06 45.26
Mengapa ukurannya sama? Apakah jarangnya hilang?
Kedua rencana kueri saat menggunakan indeks yang difilter
Informasi tambahan
select @@version
Microsoft SQL Server 2017 (RTM-CU16) (KB4508218) - 14.0.3223.3 (X64) 12 Jul 2019 17:43:08 Hak cipta (C) 2017 Edisi Pengembang Microsoft Corporation (64-bit) pada Windows Server 2012 R2 Datacenter 6.3 (Build 9600:) (Hypervisor)
Saat menjalankan kueri dan hanya memilih bidang ID , waktu cpu sebanding, dengan bacaan logis lebih rendah untuk tabel jarang.
Ukuran tabel
SchemaName TableName RowCounts Used_MB Unused_MB Total_MB
dbo nonsparse 1002540 89.54 0.10 89.64
dbo sparse 1002540 27.95 0.20 28.14
Saat memaksa indeks yang dikelompokkan atau tidak, perbedaan waktu cpu tetap ada.
sumber
Jawaban:
Kelihatannya begitu. "Overhead" yang disebutkan dalam dokumentasi tampaknya merupakan overhead CPU.
Memprofilkan dua kueri, kueri jarang mengambil sampel CPU 367 ms, sedangkan non-jarang memiliki 284 ms CPU. Itu perbedaan 83 ms.
Di mana sebagian besar itu?
Kedua profil terlihat sangat mirip sampai mereka dapat
sqlmin!IndexDataSetSession::GetNextRowValuesInternal
. Pada titik itu, kode jarang turun jalur yang berjalansqlmin!IndexDataSetSession::GetDataLong
, yang memanggil beberapa fungsi yang sepertinya terkait dengan fitur kolom jarang (HasSparseVector
,StoreColumnValue
), dan menambahkan hingga (42 + 11 =) 53 ms.Ya, tampaknya optimisasi penyimpanan jarang tidak terbawa ke indeks nonclustered ketika kolom jarang digunakan sebagai kunci indeks. Jadi kolom kunci indeks nonclustered mengambil ukuran penuh mereka terlepas dari sparseness, tetapi kolom termasuk mengambil ruang nol jika jarang dan NULL.
Melihat
DBCC PAGE
output dari halaman indeks berkerumun dengan kolom jarang bernilai NULL, saya dapat melihat bahwa panjang rekamannya adalah 11 (4 untuk ID + 7 untuk overhead standar per-rekaman):Untuk indeks yang difilter, catatan selalu 40, yang merupakan jumlah dari semua kolom kunci (ID 4 byte + 20 byte charval + 4 byte varcharval + 4 byte intval + 8 byte big intval = 40 byte).
Untuk beberapa alasan,
DBCC PAGE
tidak termasuk overhead 7 byte di "Ukuran Rekaman" untuk catatan indeks:Ukuran indeks yang tidak disaring lebih kecil (ID 4 byte + 4 byte intval + 4 byte varcharval = 12 byte) karena dua kolom jarang termasuk kolom, yang lagi-lagi mendapatkan optimasi sparseness:
Saya kira perbedaan garis perilaku ini dengan salah satu batasan yang tercantum di halaman dokumen:
Mereka diizinkan menjadi kunci dalam indeks yang tidak tercakup, tetapi tidak disimpan, eh, jarang.
sumber