为什么SELECT到一个临时表然后MERGE并不比从源查询中MERGE慢



下面是一个使用表值函数结果的MERGE:

MERGE
Table1 d
USING
dbo.tvf_Table1(@StartDate, @EndDate) s ON d.ID = s.ID
WHEN MATCHED THEN UPDATE
SET Dest1 = Src1, Dest2 = Src2, Dest3 = Src3
WHEN NOT MATCHED THEN INSERT
VALUES(ID, Src1, Src2, Src3);

在我的环境中,这大约需要30秒(平均跑三次(。

这是相同的MERGE,但这次将函数结果放在临时表中:

SELECT
*
INTO
#Temp1
FROM
dbo.tvf_Table1(@StartDate, @EndDate)
MERGE
Table1 d
USING
#Temp1 s ON d.ID = s.ID
WHEN MATCHED THEN UPDATE
SET Dest1 = Src1, Dest2 = Src2, Dest3 = Src3
WHEN NOT MATCHED THEN INSERT
VALUES(ID, Src1, Src2, Src3);
DROP TABLE #Temp1

这花了大约31秒(平均跑了三次(。

事实上,像上面这样的54个MERGE的运行在有临时表的情况下比没有要快大约四分钟。

考虑到这几乎不科学,我本以为添加临时表步骤会显著降低查询速度。毕竟,数据是从A移动到B,然后从B移动到C,而不是从A直接移动到C。

幕后发生了什么可能导致这种情况?

与表值函数相比,临时表为优化器提供了更多的优化信息。

我很感激你期望写到桌子上的开销会让事情总体上慢下来。但是,合并查询的其余部分也需要优化,了解表的确切大小有助于优化器改进总体计划。

如果放入临时表的数据量不太大,服务器应该能够将其全部保存在内存中,而不必将其溢出到磁盘。因此,与C(可能还有A(相比,A->BB->C中的B访问起来非常便宜。通常情况下,在直接查询中,I/O成本会淹没大多数其他成本。

总的来说,如果单曲MERGE表现足够好的话,我还是更喜欢它。不要试图通过将任务分解为一系列子任务来帮助SQL Server——这是优化器的工作,虽然它可能并不总是选择一个最佳计划,但它通常会选择一个足够好的计划。

最新更新