我已经将几个大表(每个具有 >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