- 摘要
mysql表出现慢查询,单表数据量500W
700W条. 每天23W条.
措施:- 优化查询语句;
- 更改存储引擎.
- 优化索引.
详情
同事去塞班岛玩前留了个大坑,导致网站报表卡死刷不开.
STEP 1
进入后台:
1 | show processlist |
发现Query很多,show full processlist
找出查询语句,发现多表join的时候没有利用到索引.
查询语句模式如下:
1 | explain select ... |
发现没有用上索引,更改查询语句。
explain
查询计划中的type
:1
2
3
4
5
6
7
8
9
10
11
12
13const(system): 根据PRI或Unique key,只取出确定的(一行)数据,常量优化.
eq_ref: JOIN条件包括了所有索引,并且索引是Unique key.
ref: JOIN条件包括部分索引或不是Unique key.
ref_or_null: WHERE col=exp or col is null
index_merge: Where id=xx or userid=xxx. 索引合并优化.
unique_subquery: where col in( select id from xxx). 这里id唯一.
index_subquery: 同上,只是id不唯一.
range: 索引在某个范围内.
all: 扫全表TODO:
研究除了子查询以外的方式使用索引.
此外, 索引对于数据类型敏感, 查询中存在字符串和date类型相等的时候, 无法利用索引,
需要将date类型转成字符串.
1 | dt = date_format(date_sub(current_date, interval 1 day), '%Y-%m-%d') |
STEP 2
检查后台,发现许多连接状态都是:waiting for table level lock
.
进一步发现这几张表的存储引擎是MYISAM
,而不是默认的innodb
.
由于myisam
引擎只有表级锁,不符合我们的使用要求.于是我把涉及到的几张表引擎都改为innodb
.
STEP 3
修改后,查询不会卡死(毕竟不扫全表了ORZ),降低到40s,但还是太慢了.
进一步检查explain结果,发现key_len
太长了.
于是重新设计索引, 把筛选度高的放前面(利用最左前缀), 并且根据具体业务\语义,尽量缩短索引字段的长度,
实在无法缩短的则取其中一部分. 最后查询缩短到0.04sec,几个报表都是秒出.