Chr*_*ler 5 common-table-expression sql-server-2008 rowlocking
在尝试避免死锁并同步来自多个服务的请求时,我正在使用ROWLOCK,READPAST.我的问题是我应该把它放在一个包含CTE,子查询和CTE上的更新语句的查询中?是否有一个关键点或三个地方都应该有它(下图)?或者也许有更好的方法来编写这样的查询,以便我只能选择将要更新的行.
alter proc dbo.Notification_DequeueJob
@jobs int = null
as
set nocount on;
set xact_abort on;
declare @now datetime
set @now = getdate();
if(@jobs is null or @jobs <= 0) set @jobs = 1
;with q as (
select
*,
dense_rank() over (order by MinDate, Destination) as dr
from
(
select *,
min(CreatedDt) over (partition by Destination) as MinDate
from dbo.NotificationJob with (rowlock, readpast)
) nj
where (nj.QueuedDt is null or (DATEDIFF(MINUTE, nj.QueuedDt, @now) > 5 and nj.CompletedDt is null))
and (nj.RetryDt is null or nj.RetryDt < @now)
and not exists(
select * from dbo.NotificationJob
where Destination = nj.Destination
and nj.QueuedDt is not null and DATEDIFF(MINUTE, nj.QueuedDt, @now) < 6 and nj.CompletedDt is null)
)
update t
set t.QueuedDt = @now,
t.RetryDt = null
output
inserted.NotificationJobId,
inserted.Categories,
inserted.Source,
inserted.Destination,
inserted.Subject,
inserted.Message
from q as t
where t.dr <= @jobs
go
Run Code Online (Sandbox Code Playgroud)
我暂时没有答案,但您可以通过多种方式了解更多信息。
你写的代码看起来很合理。检查 proc 的实际查询计划可能有助于验证 SQL Server 是否也可以生成合理的查询计划。
如果您在NotificationJob.Destination 上没有包含QueuedDt 和CompletedDt 的索引,则子not exists查询可能会获取整个表上的共享锁。这对于并发来说是可怕的。
您可以观察过程在获取锁时的行为。一种方法是暂时打开跟踪标志 1200,调用您的过程,然后关闭该标志。这将生成大量有关进程正在获取哪些锁的信息。信息量将严重影响性能,因此不要在生产系统中使用此标志。
dbcc traceon (1200, -1) -- print detailed information for every lock request. DO NOT DO THIS ON A PRODUCTION SYSTEM!
exec dbo.Notification_DequeueJob
dbcc traceoff (1200, -1) -- turn off the trace flag ASAP
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1495 次 |
| 最近记录: |