在mysql数据库的实际使用中,查询性能直接影响业务系统的响应速度,而索引是提升查询效率的核心手段。很多场景下SQL执行缓慢,往往是没有正确走索引导致的,因此掌握查看SQL是否走索引的方法,以及对应的查询优化技巧非常重要。

一、如何查看mysql中SQL是否走索引
mysql提供了explain命令,专门用于分析SQL语句的执行计划,其中就包含索引的使用情况,这是判断SQL是否走索引最常用的方式。
1. explain命令基本用法
只需要在要分析的SQL语句前加上explain关键字即可执行分析,例如分析一条查询语句:
-- 分析查询用户表中id为100的用户信息的SQL执行计划 explain select * from user where id = 100;
2. explain结果关键字段说明
执行上述命令后,会返回多个字段,其中和索引相关的核心字段如下:
| 字段名 | 含义 |
|---|---|
| key | 实际使用的索引名称,如果为NULL表示没有使用索引 |
| possible_keys | 可能使用的索引列表,是mysql优化器评估后认为可用的索引 |
| type | 访问类型,从优到差依次为system、const、eq_ref、ref、range、index、ALL,其中ALL表示全表扫描,没有走索引 |
| rows | 预估需要扫描的行数,数值越小说明索引效果越好 |
如果key字段不为NULL,且type不是ALL,基本可以判断SQL走了索引。如果key为NULL,或者type是ALL,说明SQL没有走索引,需要进行优化。
3. 其他查看方式
除了explain命令,还可以通过开启mysql的慢查询日志,配合show profile命令分析SQL执行的详细资源消耗,不过这种方式更适合定位长时间运行的慢查询,日常快速判断还是优先使用explain。
二、mysql查询优化技巧
当发现SQL没有走索引或者索引使用效果不佳时,可以通过以下技巧进行优化:
1. 合理创建和使用索引
- 优先在where条件、join关联字段、order by和group by涉及的字段上创建索引,避免在无意义的字段上建索引增加写入开销
- 避免创建重复索引和冗余索引,比如已经有(a,b)的联合索引,就不需要再单独创建a字段的索引
- 联合索引要遵循最左前缀原则,比如索引是(a,b,c),那么查询条件包含a、a+b、a+b+c时才会走索引,只包含b或者c则不会走索引
2. SQL语句编写优化
- 查询时避免使用
select *,只查询需要的字段,减少不必要的数据传输和索引覆盖失败的概率 - where条件中避免对索引字段进行函数操作、类型转换或者运算,比如
where date(create_time) = '2024-01-01'会导致索引失效,应该改成where create_time >= '2024-01-01 00:00:00' and create_time < '2024-01-02 00:00:00' - 避免使用like '%关键词%'的模糊查询,这种写法会导致索引失效,如果必须使用模糊查询,尽量使用
like '关键词%'的前缀匹配形式 - 关联查询时,尽量用小表驱动大表,同时保证关联字段上有索引
3. 其他优化手段
- 定期分析表的索引使用情况,删除无用索引,对于碎片率高的索引可以进行重建
- 对于数据量特别大的表,可以考虑分库分表,减少单表的数据量,提升查询效率
- 合理设置mysql的缓存参数,对于重复度高的查询可以适当利用查询缓存减少重复执行
三、示例演示
下面通过一个实际示例演示如何分析并优化SQL:
假设有一张订单表order,结构如下:
create table `order` ( `id` int primary key auto_increment, `user_id` int not null, `order_no` varchar(32) not null, `create_time` datetime not null, `status` tinyint not null, index idx_user_id (`user_id`), index idx_create_time (`create_time`) );
现在要查询用户ID为10,创建时间在2024年1月的订单,原始SQL如下:
select * from `order` where user_id = 10 and date(create_time) >= '2024-01-01' and date(create_time) < '2024-02-01';
使用explain分析这条SQL,会发现type可能是ALL,key为NULL,因为对create_time字段使用了date函数,导致索引失效。优化后的SQL如下:
select id,user_id,order_no,status from `order` where user_id = 10 and create_time >= '2024-01-01 00:00:00' and create_time < '2024-02-01 00:00:00';
优化点有两个,一是去掉了create_time上的date函数,让idx_create_time索引可以生效,二是把select *改成了具体需要的字段,同时可以创建联合索引idx_user_create (user_id,create_time),进一步提升查询效率。再次用explain分析,会发现key变成了新创建的联合索引,type变为range,扫描行数大幅减少。