请原谅我这是否重复.我能找到的最接近的是随机超时运行存储过程 - 删除重新创建修复,但我不确定有关重新编译存储过程的答案.
我有一个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'
在查询窗口中运行相同的选择将立即成功返回:
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
我有什么想法可以防止将来发生这种情况?谢谢.
编辑 - 添加执行计划屏幕截图
编辑 - 添加用于查看正在运行的进程的查询.在悬浮状态下,有许多人,估计大约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.
也许下一个问题是为什么索引重建或其他夜间维护对执行计划这样做?