大表复合索引,优化聚合查询

Ram*_*ams 5 mysql sql database indexing

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

我们安装 mysql 的机器有 4GB RAM

表模式

+---------------+---------------+------+-----+---------+-------+
| 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    |       |
+---------------+---------------+------+-----+---------+-------+
Run Code Online (Sandbox Code Playgroud)

索引

    +------------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| 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      |         |               |
+------------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
Run Code Online (Sandbox Code Playgroud)

查询示例

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';
Run Code Online (Sandbox Code Playgroud)

我们在像上面这样的查询上的性能非常慢,所以我想在这个表上添加复合索引

我运行以下命令

ALTER TABLE visit_views ADD INDEX domain_statstime_email (domain,stats_time,email);
Run Code Online (Sandbox Code Playgroud)

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

这是我的几个问题

1.为什么表被锁定以及为什么表不释放现有连接

2.完成索引需要多少时间。我申请了 3 小时,仍然没有创建索引。

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

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

5.这种大表添加复合索引安全吗

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

我对索引不太了解

一些统计数据

+---------------------------+
| @@innodb_buffer_pool_size |
+---------------------------+
|                3221225472 |
+---------------------------+
Run Code Online (Sandbox Code Playgroud)

O. *_*nes 1

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

WHERE domain ='our'
  AND email!=''
  AND stats_time BETWEEN '2010-06-21 00:00:00' AND '2015-08-21 00:00:00';
Run Code Online (Sandbox Code Playgroud)

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

 (email, domain, stats_time)
 (domain, email, stats_time)
Run Code Online (Sandbox Code Playgroud)

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

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

如果您没有简化向我们展示的查询,您也可以尝试使用复合覆盖索引

 (domain, stats_time, email)
Run Code Online (Sandbox Code Playgroud)

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

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

至于你的问题:

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

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

完成索引需要多少时间。我申请了 3 小时,仍然没有创建索引。

在安静的系统上速度会快得多。您也可能有一些可以删除的冗余单列索引。您可能希望复制该表并为副本建立索引,然后在准备就绪后对其进行重命名。

如何查看索引创建进度。

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

这种大表添加复合索引安全吗

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

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

可能不会。如果不需要的话,删除旧的行会有帮助。