我们在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 |
+---------------------------+
答案 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服务器中的所有操作。您需要一个命令行界面才能发出此命令。
为这种大型表添加复合索引是否安全
是的,当然,但生产系统需要时间。
如果我为此表添加分区,它会有更好的性能。
可能不是。如果你不需要它们,那么删除旧的行会有什么帮助。