War*_*Bob 8 ms-access sql-server locking
大约每周一次,我必须解决 SQL Server 2005 数据库上的阻塞链,这是由 Access 2003 前端的长期读取锁引起的。每当用户打开某个表单时就会解除锁定,并在用户完成滚动表单或关闭表单后解除锁定。由于我们的许多用户打开此表单作为参考,因此这些锁会保留一段时间。对该表的任何更新都会导致阻塞,突然间没有人可以从该表中进行选择,因为他们都在等待第一个锁。这对我们来说是一个很大的问题,因为许多应用程序都依赖于这些数据。我知道这种锁定行为是 Access 如何处理链接表的一部分。
我一直在通过 Activity Monitor 解决这个问题,只要我发现它,就会杀死任何一个是 Head Blocker 的 SELECT 进程。这是一个问题,不仅因为我手动完成它需要时间,还因为它是被动的。当我听说它时,它已经成为很多人的问题。
我想知道是否有一种自动方法来检查这些持久的阻塞链,并通过电子邮件发送或自动解决问题。逻辑看起来很简单(“如果任何与此 SELECT 查询匹配的进程阻塞了超过一分钟,请通知我/杀死它”)但我不知道如何使用 SQL Server 实现这一点。
对于它的价值,我认为正确的解决方案是修复或重写应用程序。然而,由于部门政治,这不是未来几个月的选择,所以我正在寻找一个权宜之计。
您是否考虑过使用快照隔离?在数据库中启用 read_committed_snapshot 将导致所有读取(选择)无锁:
alter database [...] set read_committed_snapshot on;
Run Code Online (Sandbox Code Playgroud)
没有应用程序更改。快照下的某些语义会发生变化,您的应用程序可能会做出奇怪的反应,但这是例外而不是常态。绝大多数应用程序没有注意到任何区别,它们只是获得了免费的性能提升。
无论如何,我还想回答最初的问题:如何检测(并可能终止)长时间运行的查询。实际上,引擎已经为您做到了。超过阈值时会引发一个事件:Blocked Process Report Event Class。该阈值是通过阻塞进程阈值 Option配置的。任何跟踪事件都可以变成一个事件通知,而事件通知可以激活程序。把这些点连起来,你就有了按需激活的代码,当引擎检测到一个查询超过了执行时间阈值时,这些代码就会运行。没有轮询,没有监控。请注意,通知是异步的,当您处理它时,查询可能已经完成,因此必须考虑到这一点。
下面是一个例子:
use msdb;
go
create queue blocked_process_report_queue;
go
create service blocked_process_report_service
on queue blocked_process_report_queue
([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification]);
create event notification blocked_process_report_notification
on server
for BLOCKED_PROCESS_REPORT
to service N'blocked_process_report_service',
N'current database';
go
sp_configure 'show advanced options', 1 ;
GO
RECONFIGURE ;
GO
sp_configure 'blocked process threshold', 20 ;
GO
RECONFIGURE ;
Run Code Online (Sandbox Code Playgroud)
现在在一个新的查询中设置一个WAITFOR
期待通知:
use msdb;
waitfor(
receive cast(message_body as xml), *
from blocked_process_report_queue);
Run Code Online (Sandbox Code Playgroud)
继续并造成一些阻塞。我使用了一个创建表但未提交的进程,并尝试从另一个查询窗口中从表中进行选择。在 20 秒内(我在上面配置的阈值),我收到了阻塞报告:
<blocked-process-report>
<blocked-process>
<process id="process1b5a24ca8" ...>
<executionStack>
<frame line="1" stmtstart="-1"... />
</executionStack>
<inputbuf>
select * from t </inputbuf>
</process>
</blocked-process>
<blocking-process>
<process status="sleeping" spid="51" ...>
<executionStack />
<inputbuf>
begin transaction
create table t (a int) </inputbuf>
</process>
</blocking-process>
</blocked-process-report>
Run Code Online (Sandbox Code Playgroud)
我将把把这个任务包装成一个自动化过程作为练习留给读者。是的,队列/服务/激活过程必须在[msdb]
.
您可以构建自己的监控工具,也可以寻找可以为您提供的第三方解决方案。如果您有兴趣构建自己的,这取决于您使用的 SQL Server 版本。如果是 2005 年,则可以使用Blocked Process Report trace event。如果您运行的是 2008 或更高版本,我建议使用等效的扩展事件,blocked_process_report。乔纳森Kehayias有一个很好的写了关于如何使用它。
如果您正在查看 3rd 方产品,Red Gate 软件的SQL Monitor内置了阻止进程和长时间运行的进程警报。
归档时间: |
|
查看次数: |
14456 次 |
最近记录: |