MySQL:具有 100+ 百万行的索引表

Posted

技术标签:

【中文标题】MySQL:具有 100+ 百万行的索引表【英文标题】:MySQL: Indexing Table With 100+ Million Rows 【发布时间】:2011-04-22 23:59:45 【问题描述】:

我发现自己陷入了困境。我有一个用于页面点击跟踪的表,有近 1.05 亿行。(!)它看起来像这样:

CREATE TABLE `media_hits` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `media_code` char(7) NOT NULL,
  `day` date NOT NULL,
  `hits` int(10) unsigned NOT NULL default '0',
  PRIMARY KEY  (`id`),
  UNIQUE KEY `media_code` (`media_code`,`day`)
) ENGINE=InnoDB;

您可以想象在此表上运行任何类型的查询都需要很长时间。一个典型的查询如下:

SELECT DISTINCT(`media_code`), COUNT(*) AS c
FROM `media_hits`
WHERE `day` >= DATE_SUB(NOW(), INTERVAL 1 DAY)
GROUP BY(`media_code`)
ORDER BY c DESC
LIMIT 200;

这个查询需要很长时间。查询中的 EXPLAIN 给了我这个:

           id: 1
  select_type: SIMPLE
        table: media_hits
         type: index
possible_keys: NULL
          key: media_code
      key_len: 10
          ref: NULL
         rows: 104773158
        Extra: Using where; Using index; Using temporary; Using filesort

这简直太糟糕了。所以我的问题是:我能做些什么呢?现在尝试添加正确的索引是不可能的。 ALTER TABLE 查询可能需要一周多的时间才能运行。我尝试删除超过 6 个月的行,但 24 小时后该查询仍在运行。

我需要解决这个问题。我唯一想到的是创建一个具有适当索引的新表,并开始在该表中记录命中。在后台,我可以有一个脚本从旧的 media_hits 表中缓慢插入记录。谁能提供有关如何索引此表的建议,以及我应该索引哪些列的一些提示?

【问题讨论】:

【参考方案1】:

您还可以查看 vertica 社区版。像

这样简单的东西
SELECT count(*) FROM event_track;
    count    
------------
1595756573
(1 row)

在最近未提交查询的系统上将在 6 秒内返回。是的,这接近 16 亿行,并且我一直在非常合理的响应时间内(通常是几秒钟,而不是几分钟)内一直在做像你上面提到的那样的查询。

好消息是,在您将实时数据从 mysql 转储到一个巨大的 csv 文件后,使用单个 COPY FROM 命令可以快速轻松地将其导入 vertica。

https://dba.stackexchange.com/a/35614/20451 有关于在哪里下载 vertica 的详细信息。

【讨论】:

【参考方案2】:

对于该特定查询,(day, media_code) 上的索引最有帮助。它仍然必须使用临时表,因为 group by 和文件排序,因为您是按 count(*) 排序的,但是该索引将显着减少它必须扫描的行数。

如果您需要比这更好的性能,那么您可能必须按照@DocBrown 所说的那样做一些聚合表。但我会先尝试索引,看看它是否有足够的帮助,然后再进行额外表的所有工作。

此外,如果您想慢慢清理旧行,而不必运行需要数天的大删除操作,您可以为删除查询添加限制。您可以批量删除它们(例如一次删除 10K 或 100K 行),以慢慢减小该表的大小,直到它小到可以添加索引。

【讨论】:

【参考方案3】:

对于这种工作,单独建立索引很可能对您没有太大帮助。更好地考虑某种缓存策略,其中包含一些额外的表来存储您需要的聚合。

例如,对于上面的查询,您可以添加第二个表“media_code_per_day”,其中包含 3 列“media_code”、“counter”和“date”。每次在原始表中插入一行时,也要相应地更新“media_code_per_day”。然后,您可以在“media_code_per_day”上运行新查询,而不是原来的查询。

当然,要在你的情况下初始化你的新表,你必须让一个批处理运行一次,遍历所有现有的行,但这只需要一次。

【讨论】:

我同意需要一个新系统,并且聚合表将有很大帮助。我想真正的问题是以一种不需要几周的方式导入旧数据。哈哈如果是这样的话,那就是它所需要的,但如果有更简单的方法就好了。

以上是关于MySQL:具有 100+ 百万行的索引表的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL Server 2017 上创建具有 800+ 百万行的现有分区表的列存储索引

如何正确索引具有 2500 万行的 SQL Server 表

具有百万行的数据库表

具有数百万行的 Django 表

mysql 索引

sql 10多万行的数据 求助