Sparsing
Durante l'esecuzione di alcuni test su colonne sparse, si è verificato un calo delle prestazioni di cui vorrei conoscere la causa diretta.
DDL
Ho creato due tabelle identiche, una con 4 colonne sparse e una senza colonne sparse.
--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
Ho quindi inserito circa 2540 valori NON NULL in entrambi.
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;
Successivamente, ho inserito i valori NULL 1M in entrambe le tabelle
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;
Interrogazioni
Esecuzione della tabella non parsimoniosa
Quando si esegue questa query due volte sulla tabella non sparse appena creata:
SET STATISTICS IO, TIME ON;
SELECT * FROM dbo.nonsparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
Le letture logiche mostrano 5257 pagine
(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.
E il tempo della CPU è di 343 ms
SQL Server Execution Times:
CPU time = 343 ms, elapsed time = 3850 ms.
esecuzione di tabelle sparse
Esecuzione della stessa query due volte sulla tabella sparsa:
SELECT * FROM dbo.sparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
Le letture sono più basse, 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.
Ma il tempo della CPU è più alto, 547 ms .
SQL Server Execution Times:
CPU time = 547 ms, elapsed time = 2406 ms.
Piano di esecuzione delle tabelle sparse
piano di esecuzione della tabella non sparsa
Domande
Domanda originale
Dato che i valori NULL non sono memorizzati direttamente nelle colonne sparse, l'aumento del tempo della CPU potrebbe essere dovuto alla restituzione dei valori NULL come set di risultati? O è semplicemente il comportamento come indicato nella documentazione ?
Le colonne sparse riducono i requisiti di spazio per i valori null a costo di un overhead per recuperare valori non null
Oppure l'overhead è correlato solo alle letture e all'archiviazione utilizzate?
Anche quando si eseguono gli sms con i risultati di scarto dopo l'esecuzione, il tempo della CPU della selezione sparsa era maggiore (407 ms) rispetto al non sparse (219 ms).
MODIFICARE
Potrebbe essere stato il sovraccarico dei valori non nulli, anche se sono presenti solo 2540, ma non sono ancora convinto.
Questo sembra avere le stesse prestazioni, ma il fattore scarso è stato perso.
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);
Sembra avere circa lo stesso tempo di esecuzione:
SQL Server Execution Times:
CPU time = 297 ms, elapsed time = 292 ms.
SQL Server Execution Times:
CPU time = 281 ms, elapsed time = 319 ms.
Ma perché le letture logiche ora hanno lo stesso importo? L'indice filtrato per la colonna sparsa non dovrebbe archiviare nulla tranne il campo ID incluso e alcune altre pagine non di dati?
Table 'sparse'. Scan count 1, logical reads 5785,
Table 'nonsparse'. Scan count 1, logical reads 5785
E la dimensione di entrambi gli indici:
RowCounts Used_MB Unused_MB Total_MB
1000000 45.20 0.06 45.26
Perché queste hanno le stesse dimensioni? La radiosità è stata persa?
Entrambi i piani di query quando si utilizza l'indice filtrato
Informazioni extra
select @@version
Microsoft SQL Server 2017 (RTM-CU16) (KB4508218) - 14.0.3223.3 (X64) 12 lug 2019 17:43:08 Copyright (C) 2017 Microsoft Corporation Developer Edition (64-bit) su Windows Server 2012 R2 Datacenter 6.3 (Build 9600:) (Hypervisor)
Durante l'esecuzione delle query e selezionando solo il campo ID , il tempo della CPU è comparabile, con letture logiche inferiori per la tabella sparsa.
Dimensione dei tavoli
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
Quando si forza l'indice cluster o non cluster, la differenza di tempo della cpu rimane.