【发布时间】:2019-09-02 09:24:58
【问题描述】:
我在建一个数据仓库,发现两个表数据比较语句有问题。我使用 EXCEPT 运算符来比较具有聚集索引的表(普通 int 字段作为键)。我的问题是,在查询执行计划中,两个聚集索引扫描后都有排序运算符。 这是一个代码示例:
create table temp.table_a
(
key_a int identity,
some_field_a int,
some_field2_a varchar(10)
);
insert into temp.table_a
(
some_field_a,
some_field2_a
)
select
n,
'abcd'
from meta.GENERATE_SEQUENCE(1,1000);
create clustered index cix_table_a_key_a on temp.table_a (key_a);
create table temp.table_b
(
key_b int identity,
some_field_b int,
some_field2_b varchar(10)
);
insert into temp.table_b
(
some_field_b,
some_field2_b
)
select
n,
'abcd'
from meta.GENERATE_SEQUENCE(1,1000);
create clustered index cix_table_b_key_b on temp.table_b (key_b);
(GENERATE_SEQUENCE 是行生成器)
现在是 EXCEPT 查询:
select
key_a,
some_field_a,
some_field2_a
from temp.table_a
except
select
key_b,
some_field_b,
some_field2_b
from temp.table_b
这是执行计划的图片:
我知道 Merge Join 需要已排序的输入,但它还不够排序吗?我的意思是,我们需要的唯一排序列是 key_a/key_b。由于聚集索引,这已经完成。不需要对其他列进行排序,因为在 key_a/key_b 的每个值内只有一行 - 无需排序。
所以,我的问题是:
- 为什么在这种情况下聚集索引扫描后还有排序运算符?
- 当我想使用 EXCEPT 运算符时,如何避免这些类型?
- 进行表格比较的更好方法(如果有的话)有哪些?
提前感谢您的回答:)
【问题讨论】:
-
不是图片,而是将实际执行计划xml上传到Paste The Plan。为避免使用排序运算符,聚集索引应位于
SELECT子句中列出的所有列上,以便提供合并运算符所需的排序。 -
这是一个粘贴到实际执行计划的计划链接:brentozar.com/pastetheplan/?id=Hk35rw9BB
-
数据未已排序。它在第一列仅排序。考虑:
(1, a, banana) EXCEPT (1, z, pineapple)。考虑第一列就足够了吗?不可以。如果您只在第一列EXCEPT然后再次查找其他数据,则可以在不排序的情况下获得EXCEPT。 -
@dominjas,如果聚集索引键是唯一的,您可以尝试使用
NOT EXISTS而不是EXCEPT。在这种情况下,也将聚集索引声明为唯一的。 -
@dominjas,感谢分享。我认为你会得到与 NOT EXISTS 相同的计划,因为 SQL Server 理解唯一索引然后使查询在语义上相同。
标签: sql sql-server indexing sql-except