2012-08-28 27 views
5

爲了避免死鎖和同步來自多個服務的請求,我使用了ROWLOCK,READPAST。我的問題是我應該把它放在一個包含CTE,子查詢和CTE更新聲明的查詢中?是否有一個關鍵點或所有三個地方都有(下方)?或者,也許有更好的方法來編寫這樣的查詢,以便我可以只選擇將要更新的行。在哪裏使用ROWLOCK,帶有CTE,子查詢和更新的READPAST?

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 

回答

1

我手邊沒有答案,但有些方法可以學到更多。

你寫的代碼看起來很合理。檢查proc的實際查詢計劃可能有助於驗證SQL Server是否也可以生成合理的查詢計劃。

如果你沒有對NotificationJob.Destination包括QueuedDt和CompletedDt的索引,not exists子查詢可能獲取共享對整個表鎖。這對併發性會很恐怖。

您可以觀察proc在獲取鎖定時的行爲。一種方法是暫時打開trace flag 1200,打電話給你的proc,然後關掉國旗。這將產生很多有關哪些鎖定proc正在獲取的信息。信息量會嚴重影響性能,因此請勿在生產系統中使用此標誌。

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