文章目录
问题描述
问题分析
总结
今天给大家分析一个由于 MySQL 字符集不一致导致索引失效的案例。
问题描述
有个朋友给我发来一个问题,说是他们的系统有几十万用户,某个查询需要 5 秒以上的时间才能返回,同时服务器 CPU 资源占用率将近 100%。这个对于用户的线上操作影响非常大,那么我们就来看看如何分析和解决这个慢查询问题。
为了便于说明问题,我们对表结构进行了简化:
create table customer(
cid int auto_increment primary key,
cname varchar(50) not null,
register_time datetime not null,
recommender varchar(50) character set utf8
) engine=innodb default charset=utf8mb4;
create unique index uk_customer_cname on customer(cname);
insert into customer(cname, register_time, recommender) values('张三', now(), '');
insert into customer(cname, register_time, recommender) values('李四', now(), '张三'),('王五', now(), '李四');
customer 是用户表,其中 cid 是主键;cname 上有一个唯一索引;recommender 是用户的推荐人。
实际查询涉及了很多表,经过简化之后存在性能问题的语句如下:
select c.*
from customer c
join customer r on (c.recommender = r.cname )
where r.cid = 1
and c.register_time between now() - interval 1 day and now();
大意是查找通过某人推荐,在指定时间段内注册的用户。
问题分析
了解问题之后,首先我让他给我发来了 explain 执行计划:
explain
select c.*
from customer c
join customer r on (c.recommender = r.cname )
where r.cname = '张三'
and c.register_time between now() - interval 1 day and now();
id|select_type|table|partitions|type |possible_keys |key |key_len|ref |rows|filtered|Extra |
--|-----------|-----|----------|-----|-----------------|-----------------|-------|-----|----|--------|-----------|
1|SIMPLE |r | |const|uk_customer_cname|uk_customer_cname|202 |const| 1| 100.0|Using index|
1|SIMPLE |c | |ALL | | | | | 3| 33.33|Using where|
从结果可以看出,有一个全表扫描(type = ALL)的操作,显然这是因为 recommender 字段上缺少索引。
更多请见:http://www.mark-to-win.com/tutorial/51581.html