面试专题:MySQL索引最左匹配如何优化order by语句

2023-12-11 19:30:58 浏览数 (1)

一、前言

MySQL的索引最左匹配是指在使用索引进行查询时,会优先匹配索引的最左侧列,然后再匹配后续列。这种匹配方式可以提高查询效率,但有时候也会导致一些问题,比如在排序查询(ORDER BY)时。并且在面试中,如果涉及数据库索引,也会经常被问到如何优化order by语句。本文就基于innodb引擎,分点分析MySQL索引最左匹配如何优化order by语句,这个问题。

二、关键点验证

本文也是通过实际数据来验证使用order by各种情况的执行情况,可以通过explain查看执行计划,进而验证MySQL索引最左匹配如何优化order by。所以在验证前需要准备一下SQL,利用存储过程,先表中插入1w条数据。

表结构,目前只有主键索引,后面验证会建联合索引:(name_aga_classId)

代码语言:sql复制
CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(11) DEFAULT '',
  `age` int(11) DEFAULT '0',
  `classId` int(11) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10000 DEFAULT CHARSET=utf8;

存储过程插入1w条数据:

代码语言:javascript复制
DELIMITER //  
CREATE PROCEDURE InsertStudentData()  
BEGIN  
    DECLARE i INT DEFAULT 1;  
    WHILE i <= 10000 DO  
        INSERT INTO student (name, age, classId) VALUES (CONCAT('Student', i), RAND() * 20   1, RAND() * 10   1);  
        SET i = i   1;  
    END WHILE;  
END //  
DELIMITER ;

CALL InsertStudentData();

数据准备完成,就可以来验证order by那些情况不走索引。

order by无索引,filesort

直接按照aga,classId进行order by,表结构没有索引,

代码语言:text复制
select *
from student
ORDER BY `name`, age, classId

先看查询时间

explain 查看执行计划,发现type是ALL全表扫描,并且出现了filesort,也就mysql内部排序,这是很耗时的。

所以,可以得出结论:order by排序字段无索引,全部扫描,并且会filesort

无过滤条件不索引

接下来创建索引, KEY `idx_auc` (`name`,`age`,`classId`)

继续上面查询语句,通过explain发现,扫描的行数还是1w多,type类型还index,all区别为index类型只遍历索引树,没有到优化级别ref

如果增加一个查询条件,比如:

代码语言:text复制
select *
from student
WHERE `name` = 'Student968'
ORDER BY `name`, age, classId

可以看谁type是等于ref

所以在使用order by的时候,建议增加过滤条件,避免全表扫描。

order by非最左,filesort

order by去掉联合索引的第一个,也就不遵循最左匹配

代码语言:text复制
select *
from student
WHERE `name` = 'Student968'
ORDER BY age, classId

发现结果出现filesort

最终不能完全匹配索引,导致filesort重排序。

order by顺序错,filesort

order by使用了联合索引的三个字段,但是没有按照name`,`age`,`classId`这个样的顺序

代码语言:text复制
EXPLAIN
select *
from student
ORDER BY age,`name`,  classId

发现结果出现filesort

order by排序不一致,filesort

另一种情况,三个字段排序不一致,比如数据库默认升序的,吧classId改下desc

代码语言:text复制
EXPLAIN
select *
from student
ORDER BY `name`, age,  classId desc

发现结果出现filesort

这个应该比较好理解,索引是已经排好序的,要么按照升序,要么降序,查询的时候按照索引顺序一致。

三、回答总结

所以在使用order by的时候,遵循一句话:使用where,按照索引顺序,字段排序方向一致。那么关于这个面试,可以这样回答:

1.首先要对sql进行分析检查必要的查询字段,过滤字段,排序字段是否按顺序创建好了索引,使用explain。

2.如果查询字段不再索引中可能会产生回表操作会导致flesort,降低性能。

3.一定要有过滤字段不然不能使用索引

4.排序字段和索引顺序不一致会导致filesort,降低性能

5.多个字段排序时如果方向不一致也会导致flesort,降低性能

6.使用explain观察查询类型和索引利用情况

我正在参与2023腾讯技术创作特训营第四期有奖征文,快来和我瓜分大奖!

0 人点赞