在列存储索引扫描运算符之前消除过滤运算符

Avi*_*Avi 1 sql-server t-sql index-tuning columnstore sql-server-2017

我有一个包含数百万行的大型事实表,称为 MyLargeFactTable,它是一个聚集列存储表。

那里也有一个复合主键约束(customer_id、location_id、order_date 列)。

我还有一个临时表#my_keys_to_filter_MyLargeFactTable,具有相同的 3 列,它包含这 3 个键值的几千个 UNIQUE 组合。

以下查询为我提供了所需的结果集

...
FROM #my_keys_to_filter_MyLargeFactTable AS t
JOIN dbo.MyLargeFactTable AS m
ON m.customer_id = t.customer_id
AND m.location_id = t.location_id
AND m.order_date = t.order_date
Run Code Online (Sandbox Code Playgroud)

但我注意到事实表上的索引扫描运算符返回的行数比它应有的多(大约一百万)并将其输入到过滤器运算符中,这进一步将结果集减少到所需的几千行。

在此处输入图片说明

索引扫描操作符读取多行(它们相当宽的行)增加了 IO,并显着减慢了整个查询。

我的参数不是 sargable 吗?

如何删除 Filter 运算符并以某种方式强制 Index Scan 运算符仅读取几千行?

表定义:

create table #my_keys_to_filter_MyLargeFactTable 
(
customer_id varchar(96) not null,
location_id varchar(96) not null,
order_date date not null,
primary key clustered (customer_id,location_id,order_date)
)

create table MyLargeFactTable
(
customer_id varchar(96) not null,
location_id varchar(96) not null,
order_date date not null,
...
lot of wide decimal typed columns, and even large varchars
...
PRIMARY KEY NONCLUSTERED  (customer_id,location_id,order_date),
INDEX cci CLUSTERED COLUMNSTORE
)
Run Code Online (Sandbox Code Playgroud)

Pau*_*ite 5

如何删除 Filter 运算符并以某种方式强制 Index Scan 运算符仅读取几千行?

Filter 操作符在散列连接处应用在连接列上构建的位图。

在三个连接谓词中,只有order_date一种数据类型支持位图下推到列存储扫描。如果您查看扫描中的 Predicate,您应该会看到如下内容:

PROBE([Opt_Bitmap1005],[dbo].[MyLargeFactTable].[order_date])
Run Code Online (Sandbox Code Playgroud)

其余的连接谓词是字符串,因此将作为完整位图测试的一部分出现在过滤器中:

PROBE([Opt_Bitmap1005],
    [dbo].[MyLargeFactTable].[customer_id],
    [dbo].[MyLargeFactTable].[location_id],
    [dbo].[MyLargeFactTable].[order_date])
Run Code Online (Sandbox Code Playgroud)

将位图测试(部分)推入列存储扫描是一种优化,仅适用于可以容纳 64 位的数据类型(如date您的示例)。注意连接位图下推不同于字符串谓词下推(例如 push customer_id LIKE '%XYZ%')。

您可以通过多种方式来解决此限制。重新设计架构以便将长字符串移动到维度表并使用整数键进行引用是一种选择。

稍微不那么侵入性,您可能能够将一个整数添加checksum到列存储(遗憾的是不是作为持久计算列)和临时表,然后将其添加到连接中 - 例如从CHECKSUM(customer_id, location_id, order_date)等计算的整数。

仍然会有一个过滤器,但位图将包含校验和列,可以将其推入扫描中。这应该会显着减少传入过滤器的行数。