在下面的查询中,两个执行计划都估计将对唯一索引执行1,000次查找。
搜索是由对同一源表的有序扫描驱动的,因此看起来应该最终以相同的顺序搜索相同的值。
两个嵌套循环都有 <NestedLoops Optimized="false" WithOrderedPrefetch="true">
有人知道为什么第一个计划的成本为0.172434,而第二个计划的成本为3.01702吗?
(问题的原因是,由于明显降低了计划成本,因此向我建议了第一个查询,这是一种优化。实际上,我认为它似乎在做更多的工作,但我只是想解释这个差异。) )
设定
CREATE TABLE dbo.Target(KeyCol int PRIMARY KEY, OtherCol char(32) NOT NULL);
CREATE TABLE dbo.Staging(KeyCol int PRIMARY KEY, OtherCol char(32) NOT NULL);
INSERT INTO dbo.Target
SELECT TOP (1000000) ROW_NUMBER() OVER (ORDER BY @@SPID), LEFT(NEWID(),32)
FROM master..spt_values v1,
master..spt_values v2;
INSERT INTO dbo.Staging
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY @@SPID), LEFT(NEWID(),32)
FROM master..spt_values v1;
查询1 “粘贴计划”链接
WITH T
AS (SELECT *
FROM Target AS T
WHERE T.KeyCol IN (SELECT S.KeyCol
FROM Staging AS S))
MERGE T
USING Staging S
ON ( T.KeyCol = S.KeyCol )
WHEN NOT MATCHED THEN
INSERT ( KeyCol, OtherCol )
VALUES(S.KeyCol, S.OtherCol )
WHEN MATCHED AND T.OtherCol > S.OtherCol THEN
UPDATE SET T.OtherCol = S.OtherCol;
查询2 “粘贴计划”链接
MERGE Target T
USING Staging S
ON ( T.KeyCol = S.KeyCol )
WHEN NOT MATCHED THEN
INSERT ( KeyCol, OtherCol )
VALUES( S.KeyCol, S.OtherCol )
WHEN MATCHED AND T.OtherCol > S.OtherCol THEN
UPDATE SET T.OtherCol = S.OtherCol;
查询1
查询2
以上内容已在SQL Server 2014(SP2)(KB3171021)-12.0.5000.0(X64)上进行了测试
@Joe Obbish在评论中指出,更简单的复制将是
SELECT *
FROM staging AS S
LEFT OUTER JOIN Target AS T
ON T.KeyCol = S.KeyCol;
与
SELECT *
FROM staging AS S
LEFT OUTER JOIN (SELECT * FROM Target) AS T
ON T.KeyCol = S.KeyCol;
对于1,000个行的登台表,以上两个仍然具有相同的计划形状(带有嵌套循环),并且该计划在没有派生表的情况下看起来更便宜,但是对于10,000行的登台表和相同的目标表,上述成本差异确实改变了计划形状(完整扫描和合并连接似乎比昂贵的搜索更具吸引力)表明,这种成本差异可能会带来影响,而不仅仅是使比较计划变得更加困难。