Kolom yang jarang, waktu cpu & indeks yang difilter

10

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.

Randi Vertongen
sumber
1
Bisakah Anda mendapatkan paket untuk permintaan pasca-edit?
George.Palacios
1
@ George.Palacios menambahkannya :)
Randi Vertongen

Jawaban:

6

Atau apakah itu hanya perilaku sebagaimana dicatat dalam dokumentasi?

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.

tangkapan layar dari Perfview menunjukkan total CPU untuk utas yang menjalankan kueri

Di mana sebagian besar itu?

Kedua profil terlihat sangat mirip sampai mereka dapat sqlmin!IndexDataSetSession::GetNextRowValuesInternal. Pada titik itu, kode jarang turun jalur yang berjalan sqlmin!IndexDataSetSession::GetDataLong, yang memanggil beberapa fungsi yang sepertinya terkait dengan fitur kolom jarang ( HasSparseVector, StoreColumnValue), dan menambahkan hingga (42 + 11 =) 53 ms.

tangkapan layar perbedaan CPU untuk kolom jarang

Mengapa ukurannya sama? Apakah jarangnya hilang?

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 PAGEoutput 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):

Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP    Record Size = 11

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 PAGEtidak termasuk overhead 7 byte di "Ukuran Rekaman" untuk catatan indeks:

Record Type = INDEX_RECORD          Record Attributes =  NULL_BITMAP    Record Size = 40

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:

Record Type = INDEX_RECORD          Record Attributes =  NULL_BITMAP    Record Size = 12

Saya kira perbedaan garis perilaku ini dengan salah satu batasan yang tercantum di halaman dokumen:

Kolom jarang tidak dapat menjadi bagian dari indeks berkerumun atau indeks kunci primer unik

Mereka diizinkan menjadi kunci dalam indeks yang tidak tercakup, tetapi tidak disimpan, eh, jarang.

Josh Darnell
sumber
2
Yang bagus! Terima kasih lagi!
Randi Vertongen