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

标签 mysql

我发现自己陷入了困境。我有一个用于跟踪页面命中率的表,其中包含近 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 表中插入记录。任何人都可以提供有关如何索引此表的建议,并可能提供一些有关我应该索引哪些列的提示吗?

最佳答案

对于这种工作,单靠索引很可能帮不上什么忙。最好考虑某种缓存策略,使用一些额外的表来存储您需要的聚合。

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

当然,要根据您的情况初始化新表,您必须对所有现有行进行一次批处理,但这只需要一次。

关于MySQL:具有 100+ 百万行的索引表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3892623/

相关文章:

php - 从单选按钮输入到 php,然后添加到数据库

php - 避免在全文列中重复输入

mysql - 使用查询查询不同的表

php/mysql - while 循环..pass 结果在数组中?

mysql - 如何让 SQL 正确更新我的记录修改时间戳?

mysql - 为什么外部排序依据不能正常工作?

MYSQL:仅更新非空字段的最充分方法?

php - 选择用 pdo 获得的数组的一列的一个值

mysql - 获取两列之间大于三天的时间差 - MySQL Workbench

mysql - 如何编写一个在未找到某些内容时不会失败的连接?