スパース
スパース列でいくつかのテストを行うとき、あなたがそうであるように、直接的な原因を知りたいパフォーマンスの低下がありました。
DDL
2つの同一のテーブルを作成しました。1つはスパース列が4つあり、もう1つはスパース列がないものです。
--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
次に、約2540のNON-NULL値を両方に挿入しました。
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;
その後、1MのNULL値を両方のテーブルに挿入しました
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;
クエリ
非スパーステーブルの実行
新しく作成された非スパーステーブルでこのクエリを2回実行すると、次のようになります。
SET STATISTICS IO, TIME ON;
SELECT * FROM dbo.nonsparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
論理読み取りは5257ページを示します
(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.
そしてCPU時間は343ミリ秒です
SQL Server Execution Times:
CPU time = 343 ms, elapsed time = 3850 ms.
スパーステーブルの実行
スパーステーブルで同じクエリを2回実行します。
SELECT * FROM dbo.sparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
読み取りはより低く、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.
ただし、CPU時間は547ミリ秒と長くなります。
SQL Server Execution Times:
CPU time = 547 ms, elapsed time = 2406 ms.
ご質問
元の質問
以来NULLの値がスパース列に直接格納されていない、CPU時間の増加は、返すことに起因する可能性がNULLの結果セットとして値を?それとも、ドキュメントに記載されているような動作ですか?
スパース列は、null以外の値を取得するためのオーバーヘッドが増える代わりに、null値のスペース要件を減らします。
または、オーバーヘッドは使用される読み取りとストレージにのみ関連していますか?
実行後の破棄結果オプションを使用してssmsを実行した場合でも、非スパース選択のCPU時間は非スパース(219ミリ秒)に比べて長くなりました(407ミリ秒)。
編集
2540しかない場合でも、null以外の値のオーバーヘッドであった可能性がありますが、それでも確信はありません。
これはほぼ同じパフォーマンスのようですが、まばらな要素が失われました。
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);
ほぼ同じ実行時間を持っているようです:
SQL Server Execution Times:
CPU time = 297 ms, elapsed time = 292 ms.
SQL Server Execution Times:
CPU time = 281 ms, elapsed time = 319 ms.
しかし、なぜ論理的な読み取りが同じ量になるのでしょうか。スパース列のフィルター処理されたインデックスには、含まれているIDフィールドと他のいくつかの非データページ以外は何も格納しないでください。
Table 'sparse'. Scan count 1, logical reads 5785,
Table 'nonsparse'. Scan count 1, logical reads 5785
そして、両方のインデックスのサイズ:
RowCounts Used_MB Unused_MB Total_MB
1000000 45.20 0.06 45.26
なぜ同じサイズなのですか?まばらさが失われましたか?
フィルターされたインデックスを使用する場合の両方のクエリプラン
追加情報
select @@version
Microsoft SQL Server 2017(RTM-CU16)(KB4508218)-14.0.3223.3(X64)2019年7月12日17:43:08 Copyright(C)2017 Microsoft Corporation Developer Edition(64-bit)on Windows Server 2012 R2 Datacenter 6.3(Build 9600:)(ハイパーバイザー)
クエリを実行し、IDフィールドのみを選択している間は、CPU時間は同等であり、スパーステーブルの論理読み取りが少なくなります。
テーブルのサイズ
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
クラスター化インデックスまたは非クラスター化インデックスのいずれかを強制すると、CPU時間の差が残ります。