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

时间:2015-07-16 10:58:05

标签: 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    |       |
+---------------+---------------+------+-----+---------+-------+

索引

    +------------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| 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 |
+---------------------------+

1 个答案:

答案 0 :(得分:0)

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

 gcloud compute images list

为了使这项工作,你应该尝试以下索引,看看哪一个更好。

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

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

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

如果您还没有简化向我们展示的查询,您也可以尝试使用compound covering index

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

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

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

关于你的问题:

  

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

将索引添加到大型表可能需要很长时间。你的160美元,很大。当我们继续进行索引操作时,表的其他用户必须等待。因此,如果您从Web应用程序访问此设备,则连接会等待其变为可用。

  

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

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

  

如何查看索引创建进度。

NOT NULL将显示MySQL服务器中的所有操作。您需要一个命令行界面才能发出此命令。

  

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

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

  

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

可能不是。如果你不需要它们,那么删除旧的行会有什么帮助。