一个非常有趣的MYSQL问题(与索引,百万条记录,算法有关)。

时间:2010-05-03 17:34:08

标签: mysql indexing

这个问题很难描述,因此很难找到答案。我希望有些专家能就此分享你的意见。

我有一张约有100万条记录的表格。表结构类似于以下内容:

items{
  uid (primary key, bigint, 15)
  updated (indexed, int, 11)
  enabled (indexed, tinyint, 1)
}

场景是这样的。我必须每天选择所有记录并进行一些处理。处理每件物品大约需要3秒钟。

我编写了一个PHP脚本,每次使用以下内容获取200个项目。

select * from items where updated > unix_timestamp(now()) - 86400 and enabled = 1 limit 200;

然后,我将更新所选项目的“已更新”字段,以确保在一天内不会再次选择它。选定的查询就是这样的。

update items set updated = unix_timestamp(now()) where uid in (1,2,3,4,...);

然后,PHP将继续运行并处理不再需要任何MYSQL连接的数据。


由于我有数百万条记录,每条记录需要3秒才能处理,因此按顺序执行它绝对不可能。因此,我将每10秒执行一次PHP。

然而,随着时间的推移和表的增长,选择变得慢得多。有时,运行需要100多秒!


你们有什么建议我怎么解决这个问题?

6 个答案:

答案 0 :(得分:3)

我认为有两点值得帮助:

一个。 unix_timestamp(now()) - 86400)

...这将为每一行评估now(),通过在每次运行之前将变量设置为该值使其成为常量。

湾索引可以帮助读取但可以减慢写入速度

在更新之前考虑删除索引(DISABLE KEYS) - 然后在读取之前重新添加它们(ENABLE KEYS)。

答案 1 :(得分:2)

我不认为enabled上的索引对你有任何好处,基数太低了。删除它,你的UPDATE应该更快。

当你说每个记录需要3秒钟时,我不确定你是什么意思,你是在200个批次处理它们。你如何确定这个以及涉及哪些其他处理?

答案 2 :(得分:2)

你可以这样做:

  1. dispatcher.php:管理整个过程。
    • 从数据库中提取方便包中的项目
    • 使用包含所有UID的HTTP帖子在同一服务器上调用worker.php(我知道worker.php不需要超过UID来完成其工作)
    • 维护一个计数器,显示正在运行的worker.php个程序员。当一个启动时,计数器递增直到某个限制,当一个工人返回时,计数器递减。请参阅"Asynchronous PHP calls?“。
    • 重复,直到所有记录都被提取一次。维护MySQL LIMIT计数器,但不能使用updated
  2. worker.php:做实际的工作
    • 发布每件商品。
    • 向帮助程序表写入其已处理的每个项目的ID(该表上没有索引)
  3. dispatcher.php:做家务。
    • 所有工作人员返回后,使用帮助表在单个语句中更新主表
  4. 错误恢复
    • 由于worker.php会在每个项目完成后更新帮助程序表,因此您可以使用帮助程序表的状态从崩溃中恢复。在每个工作人员开始运行之前保存“工作包”也有助于恢复工作人员状态。
  5. 您将拥有这种多线程处理链,甚至可以将整个事物分布在多台计算机上。

答案 3 :(得分:1)

您可以在更新前尝试运行此功能:

ALTER TABLE items DISABLE KEYS;

然后当你完成更新时,

ALTER TABLE items ENABLE KEYS;

这应该比一次更新每条记录更快地重建索引。

答案 4 :(得分:0)

对于记录少于几十亿的表,主键应该是unsigned int而不是bigint。

答案 5 :(得分:0)

一个想法:

使用HANDLER,这将大大提高您的表现:

http://dev.mysql.com/doc/refman/5.1/en/handler.html