2013-03-22 68 views
0

我有兩個腳本;其中一個將行插入到數據庫中,而其他進程則是新輸入的,即未處理的行。多次插入後依次選擇

CREATE TABLE table (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, col1 VARCHAR(32), col2 VARCHAR(32)); 

所以第一個腳本做幾個單獨的插入查詢:

INSERT INTO table (id, col1 ,col2) VALUES (0, 'val1_1', 'val1_2'); 
INSERT INTO table (id, col1 ,col2) VALUES (0, 'val2_1', 'val2_2'); 
INSERT INTO table (id, col1 ,col2) VALUES (0, 'val3_1', 'val3_2'); 
... 

然後第二個腳本使用這樣的選擇未處理的行:

SELECT * FROM table WHERE id > (SELECT MAX(id FROM table_processed)) ORDER BY id LIMIT 1000; 
(do some processing) 
(for each id processed from table: INSERT INTO table_processed (id) VALUES ({table.id});) 

有時,第一個腳本將需要插入類似5000行的東西。我注意到至少有一個實例處理腳本似乎跳過了許多行(基本上跳過了其中的3000行),並想知道是什麼原因造成了這種情況,以及如何防止它(如果它跳過了一次,那麼下一次它會繼續跳過它們,因爲它使用> MAX(id))。

或者這不應該發生? (在這種情況下,我想這將不得不與第二個腳本查詢錯誤)

+0

是否可以在插入語句中爲'id'使用相同的值? – Lucas 2013-03-22 15:09:02

+0

對不起,我忘了說,id是AUTO_INCREMENT,所以0只是假的。 – 2013-03-22 16:11:39

+0

如果是AUTO_INCREMENT,則應該將它關閉:將INSERT INTO插入表(col1,col2)VALUES('val3_1','val3_2')'。 – Lucas 2013-03-22 16:14:45

回答

0

如果2個插入事務正在運行,並且稍後的事務(=獲得更高的auto_incremented id)先前完成,那些更高的自動增量對於其他事務(即:處理一個事務),較早可見ID(在尚未提交的事務中,或者甚至可能回滾一個)。每個INSERT都得到一個全局序列的ID,所以這兩個事務甚至不能有一個範圍的ID,但是創建了一個條帶化的使用範圍。一個工作的好辦法是從未依靠任何順序或auto_incremented ID的價值,不要將它們用於什麼而是標識符

最明顯的解決方案是:

  1. 不要使用MAX(ID),而是做一個LEFT JOIN表來table_processed,並使用這些尚未存在table_processed,但這可能是沉重的選擇方面。
  2. 讓INSERT在表上執行獨佔LOCK(在繁忙場景中不合需要,您似乎已經有多個併發INSERT)。
  3. 使用processed=0索引列(可能這只是默認值,並且可以在插入中省略它)執行插入操作,並且只需要SELECT .. FROM table WHERE processed=0,完成後設置爲1

一個簡單的錯誤,使是說:OK,我就每一個插入後,使交易儘快完成,這是凱明仍然脆弱的競爭條件,所以不要使用它。

+0

謝謝!這真的很有幫助,我可能會用第三種解決方案。 – 2013-03-22 16:37:40

+0

那是我的最愛;) – Wrikken 2013-03-22 16:45:05