2008-11-17 25 views
14

我有一個數據庫表,裏面有〜50K行,每行代表一個需要完成的工作。我有一個程序從數據庫中提取作業,完成作業並將結果放回到數據庫中。 (這個系統現在正在運行)使用數據庫表作爲消息/作業隊列的最佳方法

現在我想允許多個處理任務執行任務,但要確保沒有任務執行兩次(因爲性能問題不會導致其他問題)。因爲訪問是由sproce的方式,我現在雖然是替代說sproce的東西,看起來像這樣

update tbl set owner=connection_id() where avalable and owner is null limit 1; 
select stuff from tbl where owner = connection_id(); 

BTW;工人的任務可能會降低找工作和提交結果之間的聯繫。此外,我不認爲數據庫甚至會接近瓶頸,除非我弄糟那部分(每分鐘~5個工作)

這是否有任何問題?有一個更好的方法嗎?

注意:"Database as an IPC anti-pattern"在這裏只是略有傾向,因爲1)我沒有做IPC(沒有進程生成行,它們現在都已經存在),2)描述了反模式的主要抱怨是因爲進程等待消息導致數據庫上不需要的負載(在我的情況下,如果沒有消息,所有事情都可以關閉,因爲一切都完成了)

+0

Right - bad =同步IPC,在dbms上作爲一個讀作爲SELECT進行阻塞。你大概是在做這個引入異步性的策略。 – dkretz 2008-11-18 00:21:59

+0

順便說一句,如果你想把閱讀器放在定時器上,讓它們不頻繁檢查是很有用的,但是如果它們找到工作,它們可以在再次睡覺之前排空隊列。 – dkretz 2008-11-18 00:23:31

+0

請注意我的編輯:如果他們找不到工作,他們將永遠找不到工作。但是,如果這不是真的...... – BCS 2008-11-18 00:26:23

回答

12

這就是我已經在過去成功應用於:

MsgQueue表模式

MsgId identity -- NOT NULL 
MsgTypeCode varchar(20) -- NOT NULL 
SourceCode varchar(20) -- process inserting the message -- NULLable 
State char(1) -- 'N'ew if queued, 'A'(ctive) if processing, 'C'ompleted, default 'N' -- NOT NULL 
CreateTime datetime -- default GETDATE() -- NOT NULL 
Msg varchar(255) -- NULLable 

你的消息類型你所期望 - 符合流程插入和流程讀取之間契約的消息,使用XML或您的其他表示形式(例如,在某些情況下JSON會很方便)構建。

然後可以插入0到n個進程,並且0到n個進程可以讀取和處理消息。每個讀取進程通常處理單個消息類型。可以運行多個進程類型的實例來進行負載平衡。

閱讀器讀取一條消息,並在其工作時將狀態更改爲「A」。完成後,它將狀態更改爲「C」完成。它可以刪除或不刪除,具體取決於您是否要保留審計線索。 State ='N'的消息以MsgType/Timestamp順序拉取,因此在MsgType + State + CreateTime上有一個索引。

變化:
狀態爲「E」rror。
讀取器進程代碼的列。
狀態轉換的時間戳。

這提供了一個很好的,可擴展的,可見的,簡單的機制來完成許多事情,比如你所描述的。如果你對數據庫有一個基本的瞭解,那麼它是非常簡單和可擴展的。從評論


代碼:

CREATE PROCEDURE GetMessage @MsgType VARCHAR(8)) 
AS 
DECLARE @MsgId INT 

BEGIN TRAN 

SELECT TOP 1 @MsgId = MsgId 
FROM MsgQueue 
WHERE MessageType = @pMessageType AND State = 'N' 
ORDER BY CreateTime 


IF @MsgId IS NOT NULL 
BEGIN 

UPDATE MsgQueue 
SET State = 'A' 
WHERE MsgId = @MsgId 

SELECT MsgId, Msg 
FROM MsgQueue 
WHERE MsgId = @MsgId 
END 
ELSE 
BEGIN 
SELECT MsgId = NULL, Msg = NULL 
END 

COMMIT TRAN 
-1

您正試圖實現de「Database as IPC」反模式。查看它以瞭解爲什麼你應該考慮重新設計你的軟件。

+1

你怎麼知道這是一個反模式在這種情況下,或者軟件設計不合適?您無論如何都沒有任何基於此評論的背景。 – 2008-11-17 23:08:40

0

而不是擁有owner = null時,你應該將它設置爲一個假的無人記錄,而不是。搜索空值不會限制索引,您最終可能會進行表掃描。 (這是Oracle,SQL服務器可能會有所不同)

1

正如一個可能的技術變化,你可能會考慮使用MSMQ或類似的東西。

您的每個作業/線程都可以查詢消息隊列以查看是否有新作業可用。由於閱讀消息的行爲會將其從堆棧中移除,因此可以確保只有一個作業/線程會收到消息。

當然,這是假定您正在使用Microsoft平臺。

相關問題