2017-01-06 101 views
0

我有一個應用程序與SQL Server數據庫連接,並通過批量記錄循環執行各種任務,然後相應地更新數據庫(即「成功」,「錯誤」等)。SQL Server鎖定

我遇到的潛在問題是,因爲通過每條記錄(長篇故事)需要大約一分鐘左右的時間,所以如果我有多個用戶運行應用程序,那麼「數據衝突「或試圖同時處理相同記錄的用戶。如果要正確執行,這是不可能發生的。

最初,我想添加一個LOCKED列來幫助應用程序確定記錄是否已被另一個用戶打開,但是如果應用程序崩潰或要退出而沒有完成它當前的記錄,那麼它將顯示該記錄由另一個用戶無限期地打開......對嗎?或者我錯過了一個簡單的解決方案嗎?

無論如何,如果應用程序處理它們並使其他用戶可以運行該應用程序並同時將它們「鎖定」在數據庫上,那麼理想情況是什麼? SELECT不同的一組100以免重疊。那可能嗎?我試圖對此事進行一些研究,但說實話,我在SQL Server中的經驗非常有限。感謝您的幫助!

+0

如果鎖定列是足夠的解決方案,唯一的問題是潛在的崩潰只是添加一個主開鎖計劃任務運行在深夜。 – SunKnight0

+0

http://blog.sqlauthority.com/2012/11/15/sql-server-concurrency-basics-guest-post-by-vinod-kumar/ –

+0

http://stackoverflow.com/questions/1138026/sql-服務器性能與多個併發長時間運行查詢 –

回答

2

看來你正在嘗試開發一個隊列。 Wihin SQL服務器,存在用於這樣的場景中的兩個主要的解決方案:

[1] Service Broker(參見:激活,RECEIVE TOP(1)/TOP(100)

[2]使用表加上UPDATE/DELETE/SELECT TOP(100) ... FROM dbo.QueueTable WITH(READPAST, ROWLOCK)開發一個定製的隊列。這些表提示的作用如下:

  • READPASTref - see READPAST section)避免閱讀已鎖定的記錄(通過其他併發事務鎖定)

  • ROWLOCKref - see ROWLOCK section)迫使我們從行鎖=創紀錄的水平(與頁面/分區/表鎖對比)。更多的,試圖讀取和(然後)處理隊列表中的記錄的所有concurent線程都應該使用相同的數據訪問模式(READPAST, ROWLOCK)。

您可以Remus的博客文章在這裏中找到更多詳細信息:http://rusanu.com/2010/03/26/using-tables-as-queues/從表中讀取和處理記錄

一個模板 - 隊列可能是:

SET XACT_ABORT ON 
BEGIN TRY 
-- BEGIN TRAN 

CREATE TABLE #SelectedRecords TABLE (
... 
) 
DELETE TOP(100) FROM dbo.QueueTable WITH(READPAST, ROWLOCK) 
OUTPUT deleted.Col1, deleted.Col2, ... INTO #SelectedRecords (Col1, Cold2, ...); 

... Do something with those 100 records ... 

-- COMMIT 
END TRY 
BEGIN CATCH 
-- IF @@TRANCOUNT > 0 
-- BEGIN 
--  ROLLBACK 
-- END 
END CATCH 

如果註釋行是聯合國評論說,SQL Server將在從隊列表讀取數據期間以及在數據處理期間使用一個TX。如果一個異常被catch塊攔截,那麼SQL Server將回滾當前TX(包括那些從隊列表中讀取和刪除的100條記錄)。

注意:理想情況下,數據處理塊不應該打開/創建另一個/嵌套的TX。

注2:你應該檢查是否索引(或堆結構)上隊列表支持定義(或不​​)從而行鎖:

SELECT i.allow_row_locks, * 
FROM sys.indexes i 
WHERE i.object_id = OBJECT_ID('dbo.QueueTable') 

說明#3:如果allow_row_locks位爲假/ 0,那麼你可以改變它使用

ALTER INDEX index_name 
ON dbo.QueueTable 
REBUILD 
WITH allow_row_locks = ON 
+0

感謝您的詳細回覆,但我仍然不完全確定這是我正在尋找的。如果數據處理不是通過SQL Server處理,而是通過服務器端代碼(例如PHP)執行特定任務,那麼這樣的工作是否會起作用?這個想法是通過SQL一次抓取100條記錄,通過PHP循環遍歷記錄並執行各種任務,然後根據這些任務的結果更新數據庫的「Completed」或「Error」等等。 –

+1

是。這是可能的。對於Service Broker,有所謂的「外部激活器」(搜索關鍵字:sql server服務代理外部激活器)。對於隊列表,我將添加一個列狀態,其中包含以下允許的值:0個新處理,1個處理,2個處理沒有錯誤,-1個處理有錯誤。要從隊列中獲得其他100個項目,我將使用 –

+1

更新qt top(100)set Status = 1插入輸出*從dbo.QueueTable中,qt與(readpast,rowlock)Where Status = 0 –