我遇到了一个非常糟糕的存储过程问题。奇怪的是,如果我运行程序需要几个小时。如果我在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触发器在语句运行几个小时后才会开始,并且它们会在合理的时间内完成。
答案 0 :(得分:0)
这通常是由于ANSI_NULLS
和QUOTED_IDENTIFIER
等不同的运行时设置造成的。我建议您在用于测试查询的同一SSMS选项卡(同一会话)中重新创建存储过程和视图。这将确保两者使用相同的设置。我想你会注意到两者都使用相同的计划。