损坏的Azure SQL存储过程只能通过drop recreate

时间:2016-01-07 15:40:23

标签: sql-server stored-procedures azure-sql-database

请原谅我,如果这是重复的话。我能找到的最接近的是Random timeout running a stored proc - drop recreate fixes,但我不确定那里有关于重新编译存储过程的答案。

我有一个Azure SQL数据库,最新版本,具有来自Azure Web应用程序前端的大量流量。我有一个夜间远程作业,运行批处理来重建Azure SQL数据库上的索引,因为这似乎有助于控制数据库大小和性能。

通常,重建索引大约需要20分钟。昨晚它在2小时后超时。该批处理中的错误处理程序未记录任何错误。

重建索引启动后不久,一个特定的存储过程开始为每个调用它的客户端计时。使用相同表的其他存储过程没有任何问题。当我发现问题时,我可以通过改变存储过程立即返回来缓解所有超时和暂停进程。当我再次更改存储过程以使其正常运行时,问题立即重新出现。我的理解是,更改存储过程会强制它重新编译,但这并没有解决它。

最终,我完全放弃并使用原始代码重新创建了该过程,问题得到了解决。

此程序及其使用的架构已经完全稳定了好几个月。程序本身很简单:

CREATE Procedure [dbo].[uspActivityGet] (@databaseid uniqueidentifier) AS
begin
    SET NOCOUNT ON;
    --There may be writing activities to the table asynchronously, do not use nolock on tblActivity - the ActivityBlob might be null in a dirty read.
    select top 100 a.Id, h.HandsetNumber, a.ActivityBlob, a.ActivityReceived
    from dbo.tblDatabases d with(nolock) join dbo.tblHandsets h with(nolock) on d.DatabaseId = h.DatabaseId join dbo.tblActivity a on h.Id = a.HandsetId
    where d.DatabaseId = @databaseid and a.ActivitySent is null
    order by a.ActivityReceived
end

虽然程序会因此而挂起并超时:

exec dbo.uspActivityGet 'AF3EA01B-DB22-4A39-9E1C-D096D2DF1215'

在查询窗口中运行相同的select将立即成功返回:

declare @databaseid uniqueidentifier; set @databaseid = 'AF3EA01B-DB22-4A39-9E1C-D096D2DF1215'
select top 100 a.Id, h.HandsetNumber, a.ActivityBlob, a.ActivityReceived
from dbo.tblDatabases d with(nolock) join dbo.tblHandsets h with(nolock) on d.DatabaseId = h.DatabaseId join dbo.tblActivity a on h.Id = a.HandsetId
where d.DatabaseId = @databaseid and a.ActivitySent is null
order by a.ActivityReceived

我有什么想法可以防止将来发生这种情况?谢谢。

编辑 - 添加执行计划屏幕截图 Execution Plan of stored procedure above

编辑 - 添加用于查看正在运行的进程的查询。在悬浮状态下,有许多人,估计大约150个,他们都是同一个存储过程 - uspActivityGet。此外,数据IO百分比在峰值需求时间通常运行20-40%的整个时间内最大化。我不记得等待类型是什么。以下是用于查看该查询的查询。

select * from sys.dm_Exec_requests r with(nolock) CROSS APPLY sys.dm_exec_sql_text(r.sql_handle)  order by r.total_elapsed_time desc

编辑 - 今晚又发生了一次。这是问题期间相同程序的执行计划。在再次删除并创建过程后,执行计划恢复正常并且问题已解决。

在问题发生期间,具有相同查询的sp_executesql大约需要5分钟才能执行,我相信这代表了正在发生的事情。大约有50个uspActivityGet实例被挂起,等待类型为SLEEP_TASK或IO_QUEUE_LIMIT。

也许下一个问题是为什么索引重建或其他夜间维护对执行计划执行此操作?

enter image description here

1 个答案:

答案 0 :(得分:1)

线索在查询和麻烦的执行计划中。见Poor Performance with Parallelism and Top

正常的执行计划看起来非常有效,只要相关模式不变,就不需要重新编译。我还想在这个查询中避免并行性。我在查询中添加了以下两个选项以确保两个点,并且所有人都很高兴。

OPTION (KEEPFIXED PLAN, MAXDOP 1)