我遇到了一个执行非常糟糕的存储过程的问题。奇怪的是,如果我运行该程序需要几个小时。如果我在 ssms 中将程序的内容作为批处理运行,它会在合理的时间内运行。我已将问题缩小到 proc 中的单个语句。
我的第一个想法是一个糟糕的查询计划缓存。但是,将 WITH RECOMPILE 添加到 proc 或 OPTION(RECOMPILE) 到 proc 中的违规语句没有任何区别。
因此,我从执行过程和直接运行语句中捕获了(实际)执行计划,并发现了这种差异:
慢速存储过程版本<Merge ManyToMany="True">
在 xml 中有一个元素,而普通 sql 版本有一个<Hash>
元素。
我认为我对执行计划了解得不够多,无法确定它为什么会选择一个或另一个。
两个版本都在相同的数据上运行——等等:
BEGIN TRANSACTION;
exec myproc; --capture plan
ROLLBACK TRANSACTION;
BEGIN TRANSACTION
SQL Statements from procedure -- capture 2nd plan
ROLLBACK TRANSACTION
当直接从 ssms 执行时,哪些类型的事情会影响程序中的计划?有人对如何进一步缩小范围有任何建议吗?
我不知道特定查询在这里有多大帮助,但它是一个 MERGE 语句:
MERGE schema.UpdatableView FORUPDATE
USING
(
large select statement that's not part of the problem
) DATA
ON DATA.field = FORUPDATE
WHEN MATCHED THEN -- 50% of the cost is here
UPDATE SET
LOTS of field updates
WHEN NOT MATCHED THEN -- other 50% is here
INSERT (FIELDS)
VALUES (FIELDS
OPTION (RECOMPILE)
;
可更新视图可能是问题的一部分,但 SQL Profiler 似乎并不这么认为。视图上的基础 INSERT 和 UPDATE 触发器直到语句运行几个小时后才开始,并且它们在合理的时间内完成。