执行计划 - sql与存储过程中的哈希与合并

时间:2012-07-23 17:50:00

标签: sql-server sql-execution-plan

我遇到了一个非常糟糕的存储过程问题。奇怪的是,如果我运行程序需要几个小时。如果我在ssms中作为批处理运行该过程的内容,它将在合理的时间内运行。我已经将问题缩小到了proc中的单个语句。

我的第一个想法是错误的查询计划缓存。但是,将PRO RECOMPILE添加到proc或者OPTION(RECOMPILE)到proc中的违规语句没有任何区别。

所以我从执行程序和直接运行语句中捕获了(实际)执行计划,发现了这个区别:

慢速存储过程版本在xml中有一个<Merge ManyToMany="True">元素,而普通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触发器在语句运行几个小时后才会开始,并且它们会在合理的时间内完成。

1 个答案:

答案 0 :(得分:0)

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