mysql - 将数据库记录分为已处理/未处理的有效策略

标签 mysql performance indexing partitioning

我经常遇到这个用例:

我有一个队列表,其中有大量(数百万)条记录需要处理(与远程 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/

相关文章:

mysql - 如何批量编辑和替换MySQL数据库行,使用列表替换所有行?

bash - 如果子进程失败,则返回非零退出状态

MySQL:使用自然主索引或在给定表时添加代理索引

java - 将 mysql 连接到 Java netbeans 时出错

mysql - 在django中采样mysql结果

linux - 测量进程在 IO 上花费的总时间

sql - 为什么我的mysql不使用索引?

python - 在二维张量上滚动具有可变步长值的行

最后一个 CSV 列中的 MySQL NULL 可能

java - 下载文件太慢了