我经常遇到这个用例:
我有一个队列表,其中有大量(数百万)条记录需要处理(与远程 API 同步,...)。
传统上我会使用以下方法:
CREATE TABLE Queue (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
...
processed TINYINT(1) UNSIGNED NOT NULL DEFAULT 0
);
批处理过程如下所示:
从已处理队列中选择 ... = 0 LIMIT n;
- 根据记录执行任务
更新队列集已处理 = 1 WHERE id IN(...);
- 冲洗并重复
按原样使用此方法时,SELECT
可能会产生全表扫描(对于第一批来说这可能足够快,但随着表中的第一条记录逐渐变得越来越慢) processed=1
并且 SELECT
无论如何都必须读取它们)。
我只能看到两个提高性能的选项:
在processed
列上添加索引
索引的基数非常低 (0|1
) 可能根本不会提高性能。
对表进行分区
对processed
列进行分区将使SELECT
变得非常快(假设没有使用ORDER BY
子句),因为它只返回n
分区中的第一条记录。
然而,UPDATE
会带来性能损失,它必须将记录从一个分区移动到另一个分区。
对于这个相当常见的用例,我是否错过了一种性能更好的方法?
最佳答案
根据评论:提供主键的值可以显着加快选择速度。当使用 MySQL 处理队列时,最好记住最后处理的 id 值是什么并将其保存在某个地方。对主键列执行范围查询,例如:
SELECT ... FROM Queue WHERE id BETWEEN 10000 AND 20000 LIMIT N;
产生明显更快的结果。我没有测量任何东西,但是对于使用 MySQL 作为队列机制的人来说 - 上述队列检索的修改应该会产生显着的结果。
您的里程可能会根据自动增量之间的差距等而变化,因此在实现之前应谨慎使用上述方法并进行测量。
关于mysql - 将数据库记录分为已处理/未处理的有效策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44627156/