稀疏
当像您一样对稀疏列进行一些测试时,我想知道造成性能下降的直接原因。
DDL
我创建了两个相同的表,一个表具有4个稀疏列,而一个表没有稀疏列。
--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;
查询
非稀疏表执行
在新创建的非稀疏表上运行此查询两次时:
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.
稀疏表执行
在稀疏表上两次运行相同的查询:
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 ms。
SQL Server Execution Times:
CPU time = 547 ms, elapsed time = 2406 ms.
问题
原始问题
由于NULL值未直接存储在稀疏列中,因此cpu时间的增加是否可能是由于将NULL值作为结果集返回?还是仅仅是文档中指出的行为?
稀疏列减少了空值的空间要求,但代价是检索非空值的更多开销
还是仅与读取和存储相关的间接费用?
即使运行带有执行后丢弃结果选项的ssms,与非稀疏(219 ms)相比,稀疏选择的cpu时间也较高(407 ms)。
编辑
即使只有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版权所有(C)2017 Windows Server 2012 R2 Datacenter 6.3(Build)上的Microsoft Corporation Developer Edition(64位) 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时间差仍然存在。