我有两个表,它们具有相同的命名,类型和索引键列。其中一个具有唯一的聚集索引,另一个具有非唯一索引。
测试设置
设置脚本,包括一些实际的统计信息:
DROP TABLE IF EXISTS #left;
DROP TABLE IF EXISTS #right;
CREATE TABLE #left (
a char(4) NOT NULL,
b char(2) NOT NULL,
c varchar(13) NOT NULL,
d bit NOT NULL,
e char(4) NOT NULL,
f char(25) NULL,
g char(25) NOT NULL,
h char(25) NULL
--- and a few other columns
);
CREATE UNIQUE CLUSTERED INDEX IX ON #left (a, b, c, d, e, f, g, h)
UPDATE STATISTICS #left WITH ROWCOUNT=63800000, PAGECOUNT=186000;
CREATE TABLE #right (
a char(4) NOT NULL,
b char(2) NOT NULL,
c varchar(13) NOT NULL,
d bit NOT NULL,
e char(4) NOT NULL,
f char(25) NULL,
g char(25) NOT NULL,
h char(25) NULL
--- and a few other columns
);
CREATE CLUSTERED INDEX IX ON #right (a, b, c, d, e, f, g, h)
UPDATE STATISTICS #right WITH ROWCOUNT=55700000, PAGECOUNT=128000;
再现
当我将这两个表连接到它们的集群键时,我期望一对多的MERGE连接,如下所示:
SELECT *
FROM #left AS l
LEFT JOIN #right AS r ON
l.a=r.a AND
l.b=r.b AND
l.c=r.c AND
l.d=r.d AND
l.e=r.e AND
l.f=r.f AND
l.g=r.g AND
l.h=r.h
WHERE l.a='2018';
这是我想要的查询计划:
(不要担心警告,它们与虚假统计信息有关。)
但是,如果我更改联接中各列的顺序,如下所示:
SELECT *
FROM #left AS l
LEFT JOIN #right AS r ON
l.c=r.c AND -- used to be third
l.a=r.a AND -- used to be first
l.b=r.b AND -- used to be second
l.d=r.d AND
l.e=r.e AND
l.f=r.f AND
l.g=r.g AND
l.h=r.h
WHERE l.a='2018';
... 有时候是这样的:
Sort运算符似乎根据声明的连接顺序对流进行排序,即c, a, b, d, e, f, g, h
,这为我的查询计划添加了阻塞操作。
我看过的东西
- 我尝试将列更改为
NOT NULL
,结果相同。 - 原始表格是使用创建的
ANSI_PADDING OFF
,但是使用创建的表格ANSI_PADDING ON
不会影响该计划。 - 我尝试了
INNER JOIN
而不是LEFT JOIN
,没有任何变化。 - 我在2014 SP2 Enterprise上发现了它,并在2017 Developer(现为CU)上创建了副本。
- 删除前导索引列上的WHERE子句确实会产生良好的计划,但是会影响结果。.::)
最后,我们要解决的问题
- 这是故意的吗?
- 我可以在不更改查询的情况下消除排序吗(这是供应商代码,所以我宁愿不要...)。我可以更改表和索引。