【问题标题】:composite index on large table, optimizing aggregate query大表复合索引,优化聚合查询
【发布时间】:2015-10-05 18:49:50
【问题描述】:

我们在 MySql 5.5 中有一个大表(大约有 1.6 亿条记录)。

我们安装 mysql 的机器有 4GB 内存

表架构

+---------------+---------------+------+-----+---------+-------+
| Field         | Type          | Null | Key | Default | Extra |
+---------------+---------------+------+-----+---------+-------+
| domain        | varchar(50)   | YES  | MUL | NULL    |       |
| uid           | varchar(100)  | YES  |     | NULL    |       |
| sid           | varchar(100)  | YES  | MUL | NULL    |       |
| vurl          | varchar(2500) | YES  |     | NULL    |       |
| ip            | varchar(20)   | YES  |     | NULL    |       |
| ref           | varchar(2500) | YES  |     | NULL    |       |
| stats_time    | datetime      | YES  | MUL | NULL    |       |
| country       | varchar(50)   | YES  |     | NULL    |       |
| region        | varchar(50)   | YES  |     | NULL    |       |
| place         | varchar(50)   | YES  |     | NULL    |       |
| email         | varchar(100)  | YES  | MUL | NULL    |       |
+---------------+---------------+------+-----+---------+-------+

索引

    +------------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table      | Non_unique | Key_name         | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| visit_views |          1 | sid_index        |            1 | sid         | A         |   157531031 |     NULL | NULL   | YES  | BTREE      |         |               |
| visit_views |          1 | domain_index     |            1 | domain      | A         |          17 |     NULL | NULL   | YES  | BTREE      |         |               |
| visit_views |          1 | email_index      |            1 | email       | A         |      392845 |     NULL | NULL   | YES  | BTREE      |         |               |
| visit_views |          1 | stats_time_index |            1 | stats_time  | A         |    78765515 |     NULL | NULL   | YES  | BTREE      |         |               |
+------------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

查询示例

SELECT count(*)
  FROM visit_views
 WHERE domain ='our'
   AND email!=''
   AND stats_time BETWEEN '2010-06-21 00:00:00' AND '2015-08-21 00:00:00';

我们的查询性能很慢,所以我想在这个表上添加复合索引

我运行了以下命令

ALTER TABLE visit_views ADD INDEX domain_statstime_email (domain,stats_time,email);

运行此命令后,我们的表被锁定,它已达到连接限制(连接限制为 1000)。现在表没有响应任何 INSERTS 和 SELECTS。

这是我的几个问题

1.为什么表被锁定,为什么表没有释放现有连接

2.完成索引需要多少时间。我申请了 3 小时前仍未创建索引。

3.如何查看索引创建进度。

4.为什么在向表中添加索引时连接限制突然增加到最大值。

5.为这种大表添加复合索引是否安全

6.如果我为这个表添加分区,它的性能会更好吗?

我对索引了解不多

一些统计数据

+---------------------------+
| @@innodb_buffer_pool_size |
+---------------------------+
|                3221225472 |
+---------------------------+

【问题讨论】:

  • 您示例中的查询只能使用domain,stats_time,email 索引的前两个字段。要使用全部 3 个,您需要将范围条件放在最后的字段 (domain,email,stats_time)。
  • 你用的是什么版本? (我正在寻找 ALTER 是否在线完成。)
  • 我们使用的是 MySql 5.5

标签: mysql sql database indexing


【解决方案1】:

您的查询具有三个条件:不等式、等式和范围。

WHERE domain ='our'
  AND email!=''
  AND stats_time BETWEEN '2010-06-21 00:00:00' AND '2015-08-21 00:00:00';

要使这项工作发挥作用,您应该尝试以下索引,看看哪个更好。

 (email, domain, stats_time)
 (domain, email, stats_time)

为什么是这些? MySQL 索引是 BTREE。也就是说,它们是按顺序排序的。因此,为了满足查询,MySQL 会在索引中找到与您的查询匹配的第一个元素。这基于域、电子邮件和起始 stats_time 值。然后它依次扫描索引以查找最后一个匹配值。一路上它计算记录,这满足您的查询。换句话说,它对 stats_time 进行范围扫描。

为什么选择?我不知道 MySQL 将如何处理您的电子邮件匹配谓词中的不等式。这就是为什么我建议尝试两者。

如果您还没有简化您向我们展示的查询,您也可以在

上尝试compound covering index
 (domain, stats_time, email)

这将立即随机访问第一个匹配的域/stats_time 组合,然后扫描到最后一个。在扫描时,它将查看索引中的电子邮件值(这就是为什么这被称为覆盖索引)并挑选出匹配的行。一路上它会计算行数。

您应该考虑声明您的 emailNOT NULL 以帮助您的不等式测试更有效地使用其索引。阅读http://use-the-index-luke.com/ 了解良好的背景信息。

关于你的问题:

为什么表被锁定以及为什么表没有释放现有连接 为什么在向表中添加索引时连接限制突然增加到最大值。

为大表添加索引可能需要很长时间。你的,有 160 兆行,很大。当我们进行索引操作时,表的其他用户必须等待。因此,如果您从网络应用程序访问它,连接会堆积起来等待它变得可用。

完成索引需要多长时间。我申请了 3 小时前仍未创建索引。

在安静的系统上会快得多。您也可能有一些可以删除的冗余单列索引。您可能希望复制表并索引副本,然后在准备好后重命名它。

如何查看索引创建进度。

SHOW FULL PROCESSLIST 将显示 MySQL 服务器中的所有操作。你需要一个命令行界面来给出这个命令。

为这种大表添加复合索引是否安全

当然可以,但是在生产系统上需要时间。

如果我为这个表添加分区,它会不会有更好的性能。

可能不会。如果您不需要它们,删除旧行会有所帮助。

【讨论】:

  • 在此表中,80% 的“电子邮件”列值为空但不为空。在这种情况下,哪个组合更好(domain_statstime_email)或(domain_email_statstime)。我想到了第一个。
  • @Jones 感谢您的评论。有什么方法可以在这个大表上更快地创建索引??
  • 更快地创建索引的唯一方法是在安静的 MySQL 服务器上进行。您可以复制表,索引副本,然后重命名原始和副本。这将允许原始表在您索引副本时保持服务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-18
  • 1970-01-01
  • 1970-01-01
  • 2021-09-03
  • 2010-10-23
  • 1970-01-01
相关资源
最近更新 更多