将数据库记录拆分为已处理/未处理的

时间:2017-06-19 09:43:54

标签: 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
);

批处理过程如下:

  • SELECT ... FROM Queue WHERE processed = 0 LIMIT n;
  • 对记录执行任务
  • UPDATE Queue SET processed = 1 WHERE id IN(...);
  • 冲洗并重复

当按原样使用此方法时,SELECT可能会产生全表扫描(这对于第一批可能足够快,但随着表中的第一个记录逐渐变为{{1}而变得越来越慢无论如何,processed=1必须阅读它们。

我只能看到两个改善效果的选项:

SELECT

上添加索引

索引的基数非常低(processed)可能根本无法改善效果。

对表格进行分区

0|1列进行分区会使processed非常快(假设没有使用SELECT子句),因为它只能返回分区中的ORDER BY个第一条记录。

然而,性能损失来自n,它必须将记录从一个分区移动到另一个分区。

对于这个相当常见的用例,我是否错过了更好的表现方法?

1 个答案:

答案 0 :(得分:1)

根据评论:提供主键的值可以显着加快选择。使用MySQL处理队列时,最好记住处理过的最后id的值是什么,并将其保存在某处。在主键列上执行范围查询,例如:

SELECT ... FROM Queue WHERE id BETWEEN 10000 AND 20000 LIMIT N;

产生明显更快的结果。我没有测量任何东西,但是对于使用MySQL作为队列机制的人来说 - 上面对队列检索的修改应该会产生显着的结果。

您的里程数因自动增量等因素而异,因此在实施前应谨慎使用上述方法。