为什么集群列存储上的统计信息更新速度比行存储上慢?

And*_*lin 7 sql-server statistics columnstore sql-server-2014 sql-server-2017

我已经将几个大型表(每个都有 >10^9 行和几十列)从 SQL Server 2014 实例上的聚集行存储移动到聚集列存储索引,并注意到这些表上的统计信息更新(默认采样,在我们的 ETL 中触发)或来自 Hallengren 脚本)现在需要更长的时间。

一个更具理论性的问题是为什么会这样?我的疯狂猜测是,统计信息更新会产生大量随机读取,这与列存储索引不能很好地配合,因为它们更适合大量数据的顺序读取。我很高兴知道更“深入”的解释。

更重要的问题是我是否可以做点什么来反对它。我已经在 SQL Server 2017 实例上尝试了针对具有单个 bigint 列(见下文)的表的测试用例,得到了相同的结果。增量统计在纸面上似乎是一个很好的解决方案。我需要重新创建所有统计对象(目前不是增量的,可能是由于历史原因),扩展 ETL 逻辑并更新我们的 Hallengren 脚本版本(我们目前使用旧版本)。如果有人能在我进入这个兔子洞之前分享他/她的经验,我将不胜感激。

重现步骤:

/*Create a rowstore and a columnstore table with a single bigint column*/
CREATE TABLE dbo.rowstore (col1 BIGINT);
GO

CREATE TABLE dbo.columnstore (col1 BIGINT);
GO

CREATE CLUSTERED COLUMNSTORE INDEX CCI_columnstore ON dbo.columnstore;
GO

/*Fill both tables with 400 * 10^6 rows. This results in a 15GB large rowstore and a 3,1GB large columnstore tables*/
;WITH e1(n) AS
(
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), -- 10
e2(n) AS (SELECT 1 FROM e1 CROSS JOIN e1 AS b), -- 10*10
e3(n) AS (SELECT 1 FROM e2 CROSS JOIN e2 AS b), -- 100*100
e4(n) AS (SELECT 1 FROM e3 CROSS JOIN e3 AS b)  -- 10000*10000
INSERT dbo.rowstore WITH (TABLOCK)
  SELECT CAST(CAST(NEWID() AS VARBINARY(8)) AS BIGINT) FROM e4;

GO 4

INSERT dbo.columnstore WITH (TABLOCK)
SELECT * FROM dbo.rowstore
GO

/*Trigger stats creation*/
SELECT TOP 1 * FROM dbo.rowstore WHERE col1>0

SELECT TOP 1 * FROM dbo.columnstore WHERE col1>0
GO

SET STATISTICS TIME, IO ON

/*This runs 1,5 seconds*/
UPDATE STATISTICS dbo.rowstore

/*This runs 8 seconds and becomes much slower than rowstore on really large tables*/
UPDATE STATISTICS dbo.columnstore
Run Code Online (Sandbox Code Playgroud)

Pau*_*ite 8

您允许 SQL Server 选择统计数据的采样率。

使用两者的特定样本再次运行测试,您应该会看到更多可比较的时间。

UPDATE STATISTICS dbo.rowstore 
WITH SAMPLE 1 PERCENT;

UPDATE STATISTICS dbo.columnstore 
WITH SAMPLE 1 PERCENT;
Run Code Online (Sandbox Code Playgroud)

或者更好

UPDATE STATISTICS dbo.rowstore 
WITH SAMPLE 1000000 ROWS;

UPDATE STATISTICS dbo.columnstore 
WITH SAMPLE 1000000 ROWS;
Run Code Online (Sandbox Code Playgroud)

由于列存储压缩,很难估计样本百分比中的行数。

在列存储上还有更多工作要做,以解压缩数据并将列组装成行。由于压缩优势和批处理模式处理,这通常可以弥补,但 DDL 计划尚不支持批处理模式。

您可以测试增量统计数据,看看它们是否适合您。它们是否获胜取决于您的优先事项。获得正确的初始样本大小可能很困难,并且优化器当前没有利用每个分区的统计信息。如果您经常更新统计数据,并且所花费的时间是您最关心的,那么这可能是正确的举措。

尽管引用的错误已得到修复,但您可能对统计数据在增量更新后消失的优秀答案中给出的一般观察结果感兴趣。