我有一个包含数百万行的大型事实表,称为 MyLargeFactTable,它是一个聚集列存储表。
那里也有一个复合主键约束(customer_id、location_id、order_date 列)。
我还有一个临时表#my_keys_to_filter_MyLargeFactTable,具有完全相同的 3 列,它包含这 3 个键值的几千个唯一组合。
下面的查询给了我想要的结果集
...
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
但我注意到事实表上的索引扫描运算符返回的行数超过了它应该返回的行数(大约一百万)并将其输入过滤器运算符,这进一步将结果集减少到所需的几千行。
索引扫描运算符读取大量行(它们非常宽的行)增加 IO,并显着减慢整个查询。
我的参数不是 sargable 吗?
如何删除过滤器运算符并以某种方式强制索引扫描运算符只读取几千行?
表定义:
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
)
Filter 操作符在散列连接处应用建立在连接列上的位图。
在三个连接谓词中,只有
order_date
一种数据类型支持位图下推到列存储扫描。如果您查看扫描中的谓词,您应该会看到如下内容:其余的连接谓词是字符串,因此将作为完整位图测试的一部分出现在过滤器中:
将位图测试(部分)推送到列存储扫描中是一种优化,仅适用于可以容纳 64 位的数据类型(如
date
您的示例中)。注意连接位图下推不同于字符串谓词下推(例如 pushcustomer_id LIKE '%XYZ%'
)。有几种方法可以解决这个限制。重新设计架构,以便将长字符串移动到维度表并使用整数键进行引用是一种选择。
稍微不那么侵入性,您可以将整数添加
checksum
到列存储(遗憾的是不是作为持久计算列)和临时表,然后将其添加到连接中 - 例如计算自CHECKSUM(customer_id, location_id, order_date)
等的整数。仍然会有一个过滤器,但位图将包括校验和列,可以将其推送到扫描中。这应该会显着减少传递给过滤器的行数。