Seyrek sütunlar, işlemci süresi ve filtrelenmiş dizinler


10

Sparsing

Seyrek sütunlarda bazı testler yaparken, yaptığınız gibi, doğrudan nedenini bilmek istediğim bir performans düşüşü vardı.

DDL

Biri 4 seyrek sütun ve diğeri seyrek sütun olmayan iki özdeş tablo oluşturdum.

--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

Daha sonra her ikisine de yaklaşık 2540 NON-NULL değer ekledim .

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;

Daha sonra, her iki tabloya 1M NULL değerler ekledim

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;

Sorguları

Kısmi tablo yürütme

Bu sorguyu yeni oluşturulan ayrılmamış tabloda iki kez çalıştırırken:

SET STATISTICS IO, TIME ON;
SELECT  * FROM dbo.nonsparse
WHERE   1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);

Mantıksal okumalar 5257 sayfayı gösterir

(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.

Ve işlemci zamanı 343 ms

 SQL Server Execution Times:
   CPU time = 343 ms,  elapsed time = 3850 ms.

seyrek tablo yürütme

Aynı sorguyu seyrek tabloda iki kez çalıştırma:

SELECT  * FROM dbo.sparse
WHERE   1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);

Okumalar daha düşük, 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.

Ancak işlemci süresi daha yüksek, 547 ms .

 SQL Server Execution Times:
   CPU time = 547 ms,  elapsed time = 2406 ms.

Seyrek tablo yürütme planı

seyrek olmayan masa yürütme planı


Sorular

Orijinal soru

Yana BOŞ değerleri seyrek sütunlarda doğrudan saklanmaz, cpu süresindeki artış dönen kaynaklanıyor olabilir BOŞ Bir sonuç olarak değerler? Yoksa sadece belgelerde belirtilen davranışlar mıdır?

Seyrek sütunlar, boş olmayan değerleri almak için daha fazla ek maliyetle boş değerlerin alan gereksinimlerini azaltır

Yoksa ek yük sadece kullanılan okuma ve depolama ile mi ilgili?

Ssms'yi yürütme seçeneğinden sonra silme sonuçlarıyla çalıştırırken bile, seyrek seçimin cpu süresi seyrek olmayana (219 ms) kıyasla daha yüksekti (407 ms).

DÜZENLE

Sadece 2540 mevcut olsa bile, null olmayan değerlerin yükü olabilirdi, ama hala ikna olmadım.

Bu aynı performansla ilgili gibi görünüyor, ancak seyrek faktör kaybedildi.

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);

Aynı yürütme süresine sahip gibi görünüyor:

 SQL Server Execution Times:
   CPU time = 297 ms,  elapsed time = 292 ms.

 SQL Server Execution Times:
   CPU time = 281 ms,  elapsed time = 319 ms.

Ama şimdi mantıklı okumalar neden aynı miktarda? Seyrek sütunun filtrelenmiş dizini, dahil edilen kimlik alanı ve diğer bazı veri olmayan sayfalar dışında hiçbir şey depolamamalı mı?

Table 'sparse'. Scan count 1, logical reads 5785,
Table 'nonsparse'. Scan count 1, logical reads 5785

Ve her iki endeksin büyüklüğü:

RowCounts   Used_MB Unused_MB   Total_MB
1000000     45.20   0.06        45.26

Bunlar neden aynı boyutta? Seyreklik kaybedildi mi?

Filtrelenmiş dizini kullanırken her iki sorgu planı


Fazladan bilgi

select @@version

Microsoft SQL Server 2017 (RTM-CU16) (KB4508218) - 14.0.3223.3 (X64) 12 Tem 2019 17:43:08 Telif Hakkı (C) Windows Server 2012 R2 Datacenter 6.3 (Derleme) üzerinde Microsoft Corporation Developer Edition (64 bit) 9600 :) (Hipervizör)

Sorguları çalıştırırken ve yalnızca ID alanını seçerken , seyrek tablo için daha düşük mantıksal okumalarla cpu süresi karşılaştırılabilir.

Tabloların boyutu

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

Kümelenmiş veya kümelenmemiş dizin zorlanırken, cpu zaman farkı kalır.


1
Düzenleme sonrası sorgusunun planlarını alabilir misiniz?
George.Palacios

1
@ George.Palacios ekledi :)
Randi Vertongen

Yanıtlar:


6

Yoksa sadece belgelerde belirtilen davranışlar mıdır?

Öyle görünüyor. Belgelerde belirtilen "ek yük" CPU ek yükü gibi görünüyor.

İki sorguyu belirleyen seyrek sorgu 367 ms CPU örneklemişken, seyrek olmayan 284 ms CPU'dur. Bu 83 ms'lik bir fark.

sorguyu çalıştıran iş parçacığının toplam CPU'sunu gösteren Perfview ekran görüntüsü

Bunların çoğu nerede?

Her iki profil de ulaşana kadar çok benzer görünüyor sqlmin!IndexDataSetSession::GetNextRowValuesInternal. Bu noktada, seyrek kod sqlmin!IndexDataSetSession::GetDataLong, seyrek sütun özelliğiyle ( HasSparseVector, StoreColumnValue) ilgili görünen ve (42 + 11 =) 53 ms'ye kadar eklenen bazı işlevleri çağıran bir yola gider .

seyrek sütun için CPU farkının ekran görüntüsü

Bunlar neden aynı boyutta? Seyreklik kaybedildi mi?

Evet, seyrek sütun bir dizin anahtarı olarak kullanıldığında seyrek depolama optimizasyonunun kümelenmemiş dizinlere aktarılmadığı anlaşılıyor. Kümelenmemiş dizin anahtar sütunları, seyreklikten bağımsız olarak tam boyutlarını alır, ancak dahil edilen sütunlar, seyrek ve NULL ise sıfır yer kaplar.

DBCC PAGENULL değerli seyrek sütunlarla kümelenmiş bir dizin sayfasındaki çıktıya baktığımda , kayıt uzunluğunun 11 olduğunu görebilirim (standart kayıt başına ek yükü için ID + 7 için 4):

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

Filtrelenmiş dizin için kayıt her zaman 40'tır, bu da tüm önemli sütunların boyutunun toplamıdır (4 bayt ID + 20 bayt charval + 4 bayt varcharval + 4 bayt aralığı + 8 bayt büyük aralık = 40 bayt).

Bazı nedenlerden dolayı, DBCC PAGEdizin kayıtları için "Kayıt Boyutu" na 7 bayt ek yükü dahil etmez:

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

Filtrelenmemiş dizin boyutu daha küçüktür (4 bayt ID + 4 bayt aralığı + 4 bayt varcharval = 12 bayt), çünkü seyrek sütunlardan ikisi yine seyreklik optimizasyonunu alan sütunlar içerir:

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

Davranış satırlarındaki bu farklılığın dokümanlar sayfasında listelenen sınırlamalardan biriyle olduğunu tahmin ediyorum:

Seyrek sütun, kümelenmiş bir dizinin veya benzersiz bir birincil anahtar dizininin parçası olamaz

Kümelenmemiş dizinlerde anahtar olmalarına izin verilir, ancak seyrek olarak saklanmazlar.


2
Güzel bir! Tekrar teşekkürler!
Randi Vertongen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.