大家好,我是只谈技术不剪发的 Tony 老师。今天给大家分析一个由于 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, recommender) values('李四', '张三'),('王五', '李四');
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 字段上缺少索引。