You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server 2022/Azure SQL聚集列存储GUID列段消除失效,该如何解决?

问题:uniqueidentifier列的聚集列存储段消除失效

我有一个数据集,希望存入聚集列存储,并通过uniqueidentifier类型的SubjectId列优化段消除(segment elimination)。使用的是兼容级别16的Azure SQL数据库,同时在SQL Server 2022开发者版中也验证了相同问题。根据文档,该版本应该支持基于uniqueidentifier列的段消除。

按照最佳实践,我先为数据集创建按SubjectId排序的行存储聚集索引:

CREATE CLUSTERED INDEX [MyData_CCI] 
ON [dbo].[MyData_CCS] (SubjectId)
WITH (MAXDOP = 1);

随后使用DROP_EXISTING选项创建聚集列存储索引:

CREATE CLUSTERED COLUMNSTORE INDEX [MyData_CCI]
ON [dbo].[MyData_CCS]
WITH (DROP_EXISTING = ON, MAXDOP = 1);

但生成的段似乎完全未按SubjectId对齐,且当我在WHERE子句中指定单个SubjectId查询数据时,统计信息显示段消除为0:

(44 rows affected)

Table 'MyData_CCS'. Scan count 1, logical reads 0, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 2769, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
Table 'MyData_CCS'. Segment reads 77, segment skipped 0.

我哪里操作有误?SQL Server 2022+(以及Azure SQL)难道不支持uniqueidentifier列的段消除和谓词下推吗?如上所述,SQL Server 2022开发者版也存在此问题,因此并非Azure特有问题。

复现脚本

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[MyData]') AND type in (N'U'))
DROP TABLE [dbo].[MyData]
GO
CREATE TABLE [dbo].[MyData](
    [SubjectId] [uniqueidentifier] NOT NULL,
    [SomeDateTime] [datetime] NOT NULL,
    [SomeInteger] [int] NOT NULL,
    [SomeString] [nvarchar](max) NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

-- 创建临时表存储唯一的SubjectId值
DROP TABLE #SubjectIds
CREATE TABLE #SubjectIds (
    SubjectId UNIQUEIDENTIFIER
);
GO

WITH NumberSeries AS (
    SELECT 1 AS Number
    UNION ALL
    SELECT Number + 1
    FROM NumberSeries
    WHERE Number < 42000
)
INSERT INTO #SubjectIds (SubjectId)
SELECT NEWID()
FROM NumberSeries
OPTION (MAXRECURSION 0);

-- 通过交叉连接插入2100万行数据
INSERT INTO MyData (SubjectId, SomeDateTime, SomeInteger, SomeString)
SELECT 
    s.SubjectId,
    DATEADD(SECOND, ABS(CHECKSUM(NEWID()) % 31536000), '2020-01-01'), -- 一年内的随机日期
    ABS(CHECKSUM(NEWID()) % 1000000), -- 随机整数
    REPLICATE(N'A', 100) -- 示例字符串,可按需调整
FROM 
    #SubjectIds s
    CROSS JOIN (SELECT TOP (500) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n FROM master..spt_values) AS x;

CREATE CLUSTERED INDEX [MyData_CCI] 
ON [dbo].[MyData] (SubjectId)
WITH (MAXDOP = 1, DROP_EXISTING = ON);
GO

CREATE CLUSTERED COLUMNSTORE INDEX [MyData_CCI]
ON [dbo].[MyData]
WITH (DROP_EXISTING = ON, MAXDOP = 1);

-- 查看段数据
select s.Name as SchemaName, 
       t.Name as TableName,
       i.Name as IndexName,
       c.name as ColumnName,
       c.column_id as ColumnId,
       cs.segment_id as SegmentId,
       cs.min_data_id as MinValue,
       cs.max_data_id as MaxValue
  from sys.schemas s
  join sys.tables t
    on t.schema_id = s.schema_id
  join sys.partitions as p  
    on p.object_id = t.object_id   
  join sys.indexes as I
    on i.object_id = p.object_id
   and i.index_id = p.index_id
  join sys.index_columns as ic
    on ic.[object_id] = I.[object_id]
   and ic.index_id = I.index_id   
  join sys.columns c
    on c.object_id = t.object_id
   and c.column_id = ic.column_id
  join sys.column_store_segments cs
    on cs.hobt_id = p.hobt_id
   and cs.column_id = ic.index_column_id 
WHERE t.Name = 'MyData' AND c.Name = 'SubjectId'
ORDER BY cs.segment_id

更新/解决方案

问题已解决:发现min_data_id和max_data_id元数据仅适用于数值类型。SQL Server 2022之后,GUID、字符串等类型需要查看min_deep_data和max_deep_data列。在我的案例中,即使在Azure SQL的兼容级别16数据库中新建列存储,这些列也未填充。

我不得不对受影响的列存储执行MAXDOP=1的REBUILD操作以填充元数据,之后段恢复了正常的段消除效果。具体语句如下:

ALTER INDEX [MyData_CCI] ON [dbo].[MyData] REBUILD WITH (MAXDOP = 1);

内容的提问来源于stack exchange,提问作者RMD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 09:32:34