1

我遇到了一个执行非常糟糕的存储过程的问题。奇怪的是,如果我运行该程序需要几个小时。如果我在 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 触发器直到语句运行几个小时后才开始,并且它们在合理的时间内完成。

4

1 回答 1

0

这通常是由于不同的运行时设置,如ANSI_NULLSQUOTED_IDENTIFIER。我建议您在用于测试查询的同一 SSMS 选项卡(同一会话)中重新创建存储过程和视图。这将确保两者都使用相同的设置。我想你会注意到两者都使用相同的计划。

于 2012-07-23T18:39:00.853 回答