多次插入后按顺序选择

时间:2013-03-22 15:06:17

标签: mysql

我有两个脚本;其中一个将行插入数据库,另一个处理新输入的,迄今为止未经处理的行。

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))。

或者这不应该发生? (在这种情况下,我猜它必须是第二个脚本查询的错误)

1 个答案:

答案 0 :(得分:0)

如果2个插入事务正在运行,并且稍后的事务(=获得更高的auto_incremented id)更早完成,那么更高的自动增量id在其他事务(即:您的处理事务)之前可见,然后是较低的事务(在尚未提交的事务,或者甚至可能是已回滚的事务。每个INSERT获取全局序列的id,因此这2个事务甚至不能具有单个id范围,但是创建了对所述范围的条带化使用。一个好的工作方式是 从不 依赖auto_incremented ids的顺序或值,不要将它们用于 任何 但是 标识符

最明显的解决方案是:

  1. 不要使用MAX(id),而是对table_processed执行表的LEFT JOIN,并使用table_processed中尚未存在的那些,但这在选择方面可能很重。
  2. 让INSERT在表上执行独占锁定(在繁忙场景中不合需要,您似乎已经有多个并发INSERT)。
  3. 让INSERT使用processed=0索引列完成(可能这只是默认值,您可以在插入中省略它),只需SELECT .. FROM table WHERE processed=0,设置为1完成后。
  4. 一个简单的错误就是说:好的,我只会在每次插入后执行COMMIT,以便尽快完成交易,易受竞争条件影响,所以不要不要那样用。