2013-03-22 94 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