2010-09-14 116 views
1

我遇到SQL Server 2008 sp1上的查詢通知問題。我有一個表_sys_Events多個寫入者寫入條目,並且多個讀取者使用Query Notification執行SELECT語句以立即獲取最新條目(這是通過.Net System.Data.SqlClient.SqlDependency類完成的)。我們的數據庫運行READ_COMMITTED_SNAPSHOT ON。我們還安裝了聲稱包含此問題的修復程序的累積更新包9(kb/975090)。我們所得到的是讀者和作家之間的僵局。瞭解SQL Server查詢通知的死鎖

一個典型的僵局如下:

<deadlock-list> 
<deadlock victim="processb726a508"> 
<process-list> 
    <process id="processb726a508" taskpriority="0" logused="0" waitresource="KEY: 5:72057594588758016 (0d004e5bf730)" waittime="624" ownerId="3426492" transactionname="CQueryScan::BeginNotifXact" lasttranstarted="2010-09-13T14:26:57.267" XDES="0x8079ce90" lockMode="RangeS-U" schedulerid="1" kpid="3260" status="suspended" spid="59" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2010-09-13T14:26:57.267" lastbatchcompleted="2010-09-13T14:26:57.267" clientapp=".Net SqlClient Data Provider" hostname="INETC809" hostpid="1532" loginname="bbuser" isolationlevel="read committed (2)" xactid="3426491" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056"> 
    <executionStack> 
    <frame procname="adhoc" line="1" sqlhandle="0x020000005659040700b3257e8e06defba3179cc01ffb7ca2"> 
(@1 int)SELECT [Id],[EventData],[LogDate] FROM [dbo].[_sysEvents] WHERE [Id]&gt;@1 ORDER BY [Id] ASC </frame> 
    <frame procname="adhoc" line="1" sqlhandle="0x02000000acf8f33257911a0ea68aae02722e15daa9a60023"> 
SELECT Id, EventData, LogDate FROM dbo._sysEvents WHERE Id &gt; 1425265 ORDER BY Id </frame> 
    </executionStack> 
    <inputbuf> 
SELECT Id, EventData, LogDate FROM dbo._sysEvents WHERE Id &gt; 1425265 ORDER BY Id </inputbuf> 
    </process> 
    <process id="process8db45b88" taskpriority="0" logused="8348" waitresource="KEY: 5:72057594588758016 (1200caf8f72f)" waittime="623" ownerId="3424785" transactionname="user_transaction" lasttranstarted="2010-09-13T14:26:47.157" XDES="0xf8906dc0" lockMode="RangeS-U" schedulerid="1" kpid="3656" status="suspended" spid="52" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2010-09-13T14:26:57.530" lastbatchcompleted="2010-09-13T14:26:57.530" clientapp=".Net SqlClient Data Provider" hostname="INETC1012" hostpid="3584" loginname="bbuser" isolationlevel="read committed (2)" xactid="3424785" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056"> 
    <executionStack> 
    <frame procname="adhoc" line="1" stmtstart="66" stmtend="218" sqlhandle="0x02000000d60d99067d5177738e10de6507ecd187d217792e"> 
INSERT INTO [dbo].[_sysEvents]([EventData], [LogDate]) 
VALUES (@p0, @p1) </frame> 
    <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000"> 
unknown </frame> 
    </executionStack> 
    <inputbuf> 
(@p0 varbinary(640),@p1 datetime)INSERT INTO [dbo].[_sysEvents]([EventData], [LogDate]) 
VALUES (@p0, @p1) 

SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value] </inputbuf> 
    </process> 
</process-list> 
<resource-list> 
    <keylock hobtid="72057594588758016" dbid="5" objectname="BBBets.sys.query_notification_734885935" indexname="cidx" id="lockc6f66d00" mode="RangeX-X" associatedObjectId="72057594588758016"> 
    <owner-list> 
    <owner id="process8db45b88" mode="RangeX-X"/> 
    </owner-list> 
    <waiter-list> 
    <waiter id="processb726a508" mode="RangeS-U" requestType="wait"/> 
    </waiter-list> 
    </keylock> 
    <keylock hobtid="72057594588758016" dbid="5" objectname="BBBets.sys.query_notification_734885935" indexname="cidx" id="lockc7b29380" mode="RangeS-U" associatedObjectId="72057594588758016"> 
    <owner-list> 
    <owner id="processb726a508" mode="RangeS-U"/> 
    </owner-list> 
    <waiter-list> 
    <waiter id="process8db45b88" mode="RangeS-U" requestType="wait"/> 
    </waiter-list> 
    </keylock> 
</resource-list> 
</deadlock> 
</deadlock-list> 

SELECT語句和INSERT語句在默認READ_COMMITED隔離級別,這在我們的情況下,使用行版本都做了。如您所見,鎖定發生在同一個索引對象上。我的猜測是行版本化允許發生?

有什麼我可以解決這個問題嗎?也許在SELECT語句上有不同的隔離級別?我是否應該爲我的場景使用Notification Services?

在此先感謝

+0

是您的統計數據嗎? – 2010-09-14 08:18:16

回答

2

我意識到這是一個非常晚的答覆,但以防萬一有人仍感興趣...

我從來沒有真正解決這個問題(我不認爲這是可能的)。但我確實設法找到了解決方法。我所做的是使用Service Broker。我創建了一個將消息發送到隊列的sp(每個消息代替插入 - 這個sp由多個編寫者調用),另一個sp使用該隊列。第二個sp讀取所有掛起的消息(插入),然後使用TABLOCK執行到sys_Events表的大容量插入(當消息消耗並在其自己的進程中運行時,由SqlSrv自動調用它)。

所以我實際上正在做的是收集插入,並從單個SqlSrv進程同時完成它們。 Service Broker消息和隊列是完全可靠的並且是數據庫的一部分,因此不會丟失數據完整性。如果有的話,這種方法實際上更快,實施起來相當簡單。

ps。我仍然認爲這種行爲是一個錯誤,但應該有一天會被修復!

+1

這是同樣的問題嗎? http://support.microsoft.com/kb/975090/en-us – LB40 2012-06-07 15:46:33