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

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

最佳答案

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

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)

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

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

关于您的问题:

Why table got locked and why table is not releasing existing connections Why connection limit suddenly increasing to max while adding index to table.

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

How much time it will take to complete the index. I applied 3 hours back still index not created.

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

How to see index creation progress.

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

Is it safe to add composite indexes for this kind of large table

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

If I add partitions for this table, will it any better performance.

可能不会。如果您不需要旧的行,将会有所帮助。

关于mysql - 大表复合索引,优化聚合查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31452271/

相关文章:

sql - 创建一个易于安装的 sql 数据库的 dotnetnuke 包

具有更深子级别的树状子分类表的数据库建模

java - SpagoBI/BIRT JDBC 连接

php - 如何转义输入但未转义保存到数据库中

c# - SQL 报告 : Null Parameter

mysql - 使用两个选择进行更新

c# - System.Data.Objects.MaterializedDataRecord 不包含属性

java - 当数据来自 mySQL 时,在 java 的 Spinner 中删除重复项

PHP - 用户登录后,重定向到存储在数据库中的地址

mysql - group_concat,将一列连接成一行,如果其他列相等