索引扫描中不使用列存储索引谓词

Eya*_*man 4 sql-server execution-plan columnstore query-performance

我们正在使用包含约 50M 记录的聚集列存储索引表,与使用相同的数据库架构和数据(刚刚导出和导入 bak 文件)在本地运行相比,在GCP云 sql 上运行时会遇到很大的性能下降。

使用下面的查询,我们发现GCP云sql( https://www.brentozar.com/pastetheplan/?id=ByexjqpCF )上的执行计划没有在索引扫描上使用projectId谓词,而是仅将其应用于进一步的过滤步骤。在本地运行时(https://www.brentozar.com/pastetheplan/?id=rJLO59pRK),谓词被推入索引扫描,从而减少扫描行数并提高性能。

造成这种差异的原因是什么?

SELECT YEAR(ReferenceDate) RefDateYear, MONTH(ReferenceDate) RefDateMonth,sum(diffsum) DiffSum
into #res
FROM Journal jp
WHERE jp.projectId='582b02e2-add0-4b50-94f7-4e7e07497cf6' AND ReferenceDate < '20220101' AND batch != 9998 
GROUP BY YEAR(ReferenceDate), MONTH(ReferenceDate)
Run Code Online (Sandbox Code Playgroud)

另请参阅表架构:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Journal](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [projectId] [uniqueidentifier] NOT NULL,
    [diffSum] [money] NOT NULL,
    [batch] [int] NOT NULL,
    [referenceDate] [datetime2](7) NOT NULL,
    ...
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Journal] ADD  CONSTRAINT [Journal_pkey] PRIMARY KEY NONCLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE CLUSTERED COLUMNSTORE INDEX [CCI_journal] ON [dbo].[Journal] WITH (DROP_EXISTING = OFF, COMPRESSION_DELAY = 0) ON [PRIMARY]
GO
Run Code Online (Sandbox Code Playgroud)

Pau*_*ite 5

SQL Server 标准版有许多与列存储性能相关的限制。

1内存中 OLTP 数据大小和列存储段缓存仅限于“规模限制”部分中的版本指定的内存量。批处理模式操作的并行度 (DOP)对于 SQL Server Standard Edition 限制为 2,对于 SQL Server Web 版和 Express Edition 限制为 1。这是指在基于磁盘的表和内存优化表上创建的列存储索引。

2聚合下推、字符串谓词下推和 SIMD 优化是 SQL Server 企业版可扩展性增强功能

来自列存储索引 - 新增功能 - 数据库兼容性级别 120 或 130 的性能

  • 字符串谓词下推可加快比较 VARCHAR/CHAR 或 NVARCHAR/NCHAR 类型字符串的查询速度。这适用于常见的比较运算符,并包括使用位图过滤器的 LIKE 等运算符。这适用于所有支持的排序规则。在 SQL Server 上,此增强功能是为企业版保留的。

尽管您的谓词是 UUID,但它在这里算作字符串谓词。如果没有字符串谓词下推,谓词将在单独的 Filter 中求值,无需特殊优化。

列存储索引 - 查询性能文档中对字符串谓词下推有更全面的描述。

字符串谓词下推利用为列创建的主/辅字典来提高查询性能。例如,让我们考虑由 100 个不同字符串值组成的行组中的字符串列段。这意味着假设有 100 万行,每个不同的字符串值平均被引用 10,000 次。

通过字符串谓词下推,查询执行会根据字典中的值计算谓词,如果它符合条件,则引用字典值的所有行都会自动符合条件。这通过两种方式提高了性能:

  1. 仅返回符合条件的行,减少需要流出 SCAN 节点的行数。

  2. 字符串比较的次数显着减少。在此示例中,仅需要 100 次字符串比较,而需要进行 100 万次比较。有一些限制,如下所述:

    • 增量行组没有字符串谓词下推。增量行组中的列没有字典。
    • 如果字典超过 64 KB 条目,则不会进行字符串谓词下推。
    • 不支持计算 NULL 的表达式。

查看标准版中的列存储有多有用?Erik Darling 的其他例子。