0
点赞
收藏
分享

微信扫一扫

MySQL之索引性能分析与优化

云竹文斋 2022-03-31 阅读 64

MySQL之索引性能分析与优化

简介

MySQL 中索引的本质是一种特殊的数据结构,可以简单理解为排好序的快速查找结构,通过索引可以提高数据检索的效率,降低数据库的 IO 成本,而通过索引列对数据进行排序,可以在降低数据排序成本的同时,降低 CPU 的消耗,故索引在 MySQL 中起着举足轻重的作用,本文将通过 EXPLAIN 关键字模拟优化器执行 SQL 查询语句,从而分析索引的性能来进行优化。

# 建表语句
CREATE TABLE student ( 
	`id` INT PRIMARY KEY AUTO_INCREMENT, 
	`name` VARCHAR(24) NOT NULL DEFAULT '' COMMENT '姓名', 
	`age` INT NOT NULL DEFAULT 0 COMMENT '年龄', 
	`major` VARCHAR(20) NOT NULL DEFAULT '' COMMENT '专业', 
	`time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入学时间' 
) CHARSET utf8 COMMENT '学生信息表' ;
	
# 插入数据
INSERT INTO student(`name`, `age`, `major`, `time`) VALUES('Tom', 18, '计算机科学与技术', NOW()); 
INSERT INTO student(`name`, `age`, `major`, `time`) VALUES('Amy', 20, '软件工程', NOW());

# 创建索引
ALTER TABLE student ADD INDEX idx_student_nameAgeMajor(`name`, `age`, `major`);

创建完成之后首先执行如下的 SQL 语句进行测试:

SELECT * FROM student

执行结果如下图,可以正常查询到表中的数据:

查询功能正常


1. 全值匹配的情况

分别执行如下 SQL 语句,分析性能方面的异同:

EXPLAIN SELECT * FROM student WHERE `name` = 'Amy' AND `age` = 20 AND `major` = '软件工程';
EXPLAIN SELECT * FROM student WHERE `age` = 20 AND `major` = '软件工程';
EXPLAIN SELECT * FROM student WHERE `name` = 'Amy' AND `major` = '软件工程';

程序执行结果如图所示:

全值匹配性能测试

分析:通过执行结果可以看出,第一个查询物尽其用,三个字段均成功匹配索引;第二个查询索引失效,未能成功匹配到索引,执行了一次全表扫描;而第三个查询只有第一个字段成功匹配到了索引,第二个字段未能成功匹配。所以我们可以得到如下结论:全值匹配性能最优,但是索引多列时需要遵循最佳左前缀法则,即查询从索引的最左前列开始并且不跳过索引中的列,否则会导致索引失效


2. 索引列操作的情况

分别执行如下 SQL 语句,分析性能方面的异同:

SELECT * FROM student WHERE LEFT(`name`, 3) = 'AMY';
EXPLAIN SELECT * FROM student WHERE LEFT(`name`, 3) = 'AMY';

SELECT * FROM student WHERE name = 'AMY';
EXPLAIN SELECT * FROM student WHERE name = 'AMY';

程序执行结果如图所示:

索引列计算的情况

分析:通过执行结果可以看出,两条 SQL 语句的执行结果完全相同,但是第一个查询使用到了库函数,导致索引失效,执行了一次全表扫描,而第二个查询完美用到了索引。所以建议不要在索引列上做任何操作(计算、函数、类型转换),这样会导致索引失效而转向全表扫描,有时遇到需要使用库函数但数据量不是大到严重影响速度时,一般可以先查出来,再在程序中去筛选

3. 范围匹配的情况

分别执行如下 SQL 语句,分析性能方面的异同:

SELECT * FROM student WHERE `name` = 'AMY' AND age > 18 AND `major` = '软件工程';
EXPLAIN SELECT * FROM student WHERE `name` = 'AMY' AND age > 18 AND `major` = '软件工程';

程序执行结果如图所示:

范围匹配的情况

分析:通过执行结果可以看出,与全值匹配的情况相比,虽然查询到的结果相同,但是 SQL 的性能明显有所下降,且范围之后的字段查询时并未使用到索引。所以我们可以得到如下结论:范围之后索引全部失效,存储引擎不能使用索引中范围条件右边的列


4. 覆盖索引的情况

分别执行如下 SQL 语句,分析性能方面的异同:

SELECT * FROM student WHERE `name` = 'AMY' AND age = 20;
EXPLAIN SELECT * FROM student WHERE `name` = 'AMY' AND age = 20;

SELECT `name`, `age` FROM student WHERE `name` = 'AMY' AND age = 20;
EXPLAIN SELECT `name`, `age` FROM student WHERE `name` = 'AMY' AND age = 20;

程序执行结果如图所示:

覆盖索引的情况

分析:通过执行结果可以看出,第二条 SQL 相比于第一条,只查询到了所需要的字段,且性能更优。所以我们在查询时尽量使用覆盖索引,即只访问索引的查询,索引列和查询列保持一致,尽可能减少 SELECT * 的查询


5. 模糊查询的情况

分别执行如下 SQL 语句,分析性能方面的异同:

EXPLAIN SELECT * FROM student WHERE `name` LIKE '%my';
EXPLAIN SELECT * FROM student WHERE `name` LIKE 'Am%';

EXPLAIN SELECT `name` FROM student WHERE `name` LIKE '%my';

程序执行结果如图所示:

模糊查询的情况

分析:通过执行结果可以看出,当使用 LIKE 关键字进行模糊查询时,以通配符开头 ‘%’ 会导致索引失效变成全表扫描,即 LIKE 百分加右边,当遇到必须使用开头的情况时,可以通过覆盖索引来解决索引失效的问题,且性能要更优


6. 其他可能导致索引失效的情况

分别执行如下 SQL 语句,分析性能方面的异同:

EXPLAIN SELECT * FROM student WHERE `name` != 'Amy';
EXPLAIN SELECT * FROM student WHERE `name` IS NOT NULL;
EXPLAIN SELECT * FROM student WHERE `name` = 'Amy' OR `name` = 'Tom';
EXPLAIN SELECT * FROM student WHERE `name` = 123;

程序执行结果如图所示:

其他可能导致索引失效的情况

分析:通过执行结果可以看出,当语句中出现不等号、NULL 值、关键字 OR 时都会导致索引失效,从而进行全表扫描,除此之外还要特别注意,字符串的单引号不能省略,MySQL 底层会自动进行类型转换从而导致索引失效。


总结

本文介绍了常见索引失效的情况与优化方案,可能导致索引失效的情况有许多,数据库的性能对整个项目工程的影响也是不容忽视的,在实际开发场景中应该尽量避免出现这样的情况,谢谢观看!

举报

相关推荐

0 条评论