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

一个非常有趣的MYSQL问题(与索引、百万记录、算法相关),mysql,indexing,Mysql,Indexing,这个问题很难描述,因此很难找到答案。我希望一些专家能与你分享这方面的意见 我有一张大约有一百万条记录的桌子。表结构类似于以下内容: items{ uid (primary key, bigint, 15) updated (indexed, int, 11) enabled (indexed, tinyint, 1) } 情况是这样的。我必须每天选择所有的记录并进行一些处理。处理每个项目大约需要3秒钟 我编写了一个PHP脚本,每次使用以下命令获取200个项目 select * fr

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

我有一张大约有一百万条记录的桌子。表结构类似于以下内容:

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

但是,随着时间的推移和表的增长,select变得越来越慢。有时,它需要超过100秒才能运行



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

我认为
enabled
上的索引对您没有任何好处,基数太低了。删除该选项,您的
更新应该会更快


我不知道你说每条记录需要3秒钟是什么意思,因为你是以200个批次处理它们的。您如何确定这一点以及涉及哪些其他处理?

您可以在更新之前尝试运行此操作:

ALTER TABLE items DISABLE KEYS;
然后当你完成更新后

ALTER TABLE items ENABLE KEYS;

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

我认为有两点应该有所帮助:

a。unix_时间戳(now())-86400)

。。。这将对每一行立即求值(),在每次运行之前将变量设置为该值,使其成为常量

b。索引有助于读取,但会减慢写入速度

考虑在更新(禁用键)之前删除索引,然后在读取(启用键)之前重新添加索引。

您可以这样做:

  • dispatcher.php
    :管理整个流程。
    • 从数据库获取方便的包中的项目
    • 在同一台服务器上调用
      worker.php
      ,其中包含获取的所有UID的HTTP post(我知道
      worker.php
      只需要UID即可完成其工作)
    • 维护运行的
      worker.php
      Scrip数量的计数器。当一个工作进程启动时,计数器递增,直到某个限制,当一个工作进程返回时,计数器递减。见”
    • 重复,直到所有记录都被提取一次。维护MySQL
      LIMIT
      计数器,不要使用
      updated
  • worker.php
    :实际工作是否正常
    • 对张贴的每一个项目都有自己的作用
    • 将已处理的每个项的ID写入帮助器表(该表上没有索引)
  • dispatcher.php
    :housekeping。
    • 所有worker返回后,在一条语句中使用helper表更新主表
  • 错误恢复
    • 由于worker.php会在每个项目完成后更新helper表,因此可以使用helper表的状态从崩溃中恢复。在每个worker开始运行之前保存每个worker的“工作包”也有助于恢复worker状态

  • 通过这种方式,您将拥有一个多线程处理链,甚至可以在多台机器上分发整个过程。

    对于记录数少于数十亿条的表,主键应该是未签名的int而不是bigint。

    一个想法:

    使用处理程序,这将大大提高您的性能:


    “我每天都要选择所有记录并进行一些处理。处理每个项目大约需要3秒钟。”-每天处理300万秒?听起来不可能(或非常昂贵)。此外,请向我们提供您查询的解释输出。(或者在这种情况下,我认为MySQL无法进行解释更新)注意:如果在PHP中执行异步工作变得太困难,您可以用更方便的语言实现dispatcher。以上只是一个想法,我不知道是否可行。可能需要一些修改来适应PHPs缺少本机线程的情况。在一个大表上启用键可能需要很长时间,可能不是一个好主意用于更新少量行。可能。但是,每次更新一行时,您都在更新索引(可能是以一种大的方式)。我认为,一次完成这一切比说“移动这500000个索引项”要好“每次更新时,我都会获取200个数据,并调用一些RESTAPI。RESTAPI的往返时间约为3秒。有时,API会返回错误,我必须将enabled设置为0,并且该项将不再被提取。@terence410:听起来问题似乎与SQL或PHP无关-是REST API速度慢。如果这是您的代码,那么您很幸运,您可以尝试改进它的性能。如果没有,你也无能为力。