我有两个脚本;其中一个将行插入数据库,另一个处理新输入的,迄今为止未经处理的行。
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 :(得分:0)
如果2个插入事务正在运行,并且稍后的事务(=获得更高的auto_incremented id)更早完成,那么更高的自动增量id在其他事务(即:您的处理事务)之前可见,然后是较低的事务(在尚未提交的事务,或者甚至可能是已回滚的事务。每个INSERT获取全局序列的id,因此这2个事务甚至不能具有单个id范围,但是创建了对所述范围的条带化使用。一个好的工作方式是 从不 依赖auto_incremented ids的顺序或值,不要将它们用于 任何 但是 标识符 。
最明显的解决方案是:
processed=0
索引列完成(可能这只是默认值,您可以在插入中省略它),只需SELECT .. FROM table WHERE processed=0
,设置为1
完成后。一个简单的错误就是说:好的,我只会在每次插入后执行COMMIT,以便尽快完成交易,仍易受竞争条件影响,所以不要不要那样用。