我正在使用PHP和MySQL 5.6.17(InnoDB)实现一个队列,我想选择前N个匹配的行,然后将它们标记为正在处理。
我需要将行标记为正在处理,因为查询是由多个并行运行的脚本执行的(因此我需要阻止脚本选择相同的行)。
我写了以下查询:
START TRANSACTION;
SELECT id, col2, col3
FROM table
WHERE col4 = 1 AND date_update_started < UTC_TIMESTAMP() - INTERVAL 12 HOUR
ORDER BY col5 DESC, col6 ASC
LIMIT 100 FOR UPDATE;
#update the above selected rows to mark them as being processed
UPDATE table SET date_update_started = UTC_TIMESTAMP() WHERE id IN (
SELECT id, col2, col3 #same query as above
FROM table
WHERE col4 = 1 AND date_update_started < UTC_TIMESTAMP() - INTERVAL 12 HOUR
ORDER BY col5 DESC, col6 ASC
LIMIT 100
);
COMMIT;
但是,在测试查询的更新部分时,我收到以下错误:
[Err] 1235 - 这个版本的MySQL还没有支持&#39; LIMIT&amp; IN / ALL / ANY / SOME子查询&#39;
如何修改此查询,以便它选择前N个匹配行并更新这些行上的date_update_started
列,以便并行执行此查询的脚本不会选择它们?
答案 0 :(得分:1)
确保脚本的每个实例都具有唯一ID。您可以在运行时将其作为命令行参数传递。
在队列表中添加一列:
scriptId INT DEFAULT NULL
- 用它锁定一些行;保留锁定它们的脚本的ID。此代码会锁定某些行:
UPDATE `table`
SET lockId = 123 # Replace '123' (in PHP) with the ID of the script that runs the query
WHERE lockId IS NULL
AND ... # put your own conditions here to select the entries you want to process
LIMIT 100 # change '100' with the number of entries you want to lock in a batch
然后运行:
SELECT *
FROM `table`
WHERE lockId = 123 # The same value as above
获取锁定的行。
处理完每一行后,您可以将其从表格中删除,也可以将状态字段设置为“已处理”。并使用它在上面的锁定查询中过滤掉它。
备注:如果您完全确定处理脚本在处理期间永不崩溃,则此方法很有效。如果它崩溃,它会使行被锁定。如果在下次运行时它使用相同的script ID
,它将尝试处理锁定的行。这可以通过在脚本退出时解锁行来解决。