#插入一些示例数据
 drop procedure if exists insert_emp;
 delimiter ;;
 create procedure insert_emp()
 begin
 declare i int;
 set i=1;
 while(i<=100000)do
 insert into employees(name,age,position) values(CONCAT('tqq',i),i,'dev');
 set i=i+1;
 end while;
 end;;
 delimiter ;
 call insert_emp();
 
 EXPLAIN SELECT * FROM employees WHERE name > 'LiLei' AND age = 22 AND position ='manager';

1、联合索引第一个字段范围不会走索引

 EXPLAIN SELECT * FROM employees WHERE name > 'LiLei' AND age = 22 AND position ='manager';

在这里插入图片描述
结论:联合索引一个字段就用返回查找不会走索引,MySQL内部可能觉得第一个字段就用范围结果应该很大,回表效率不高,还不如走全表扫描

2、强制走索引

 EXPLAIN SELECT * FROM employees force index(idx_name_age_position) WHERE name > 'LiLei' AND age = 22 AND position ='manager';

在这里插入图片描述
结论:虽然使用强制走索引让联合索引第一个字段范围查找也走索引,扫描的行rows看上去也少了点,但是最终查找效率不一定比全表扫描高,因为回表效率不高

 ‐‐ 关闭查询缓存
 set global query_cache_size=0;
 set global query_cache_type=0;
 ‐‐ 执行时间0.333s
 SELECT * FROM employees WHERE name > 'LiLei';
 ‐‐ 执行时间0.444s
 SELECT * FROM employees force index(idx_name_age_position) WHERE name > 'LiLei';

3、覆盖索引优化

查询结果集符合最左前缀原则,减少回表

 EXPLAIN SELECT name,age,position FROM employees WHERE name > 'LiLei' AND age = 22 AND position ='manager';

在这里插入图片描述

4、inor在表数据量比较大的时候会走索引,在表记录不多的情况下会选择全表扫描

 EXPLAIN SELECT * FROM employees WHERE name in ('LiLei','HanMeimei','Lucy') AND age = 22 AND position ='manager';

在这里插入图片描述

 EXPLAIN SELECT * FROM employees WHERE name in ('LiLei','HanMeimei','Lucy') AND age = 22 AND position ='manager';

在这里插入图片描述
一个实验,将employees 表复制一张employees_copy的表,里面保留两三条记录

 
 EXPLAIN SELECT * FROM employees_copy WHERE name in ('LiLei','HanMeimei','Lucy') AND age = 22 AND position ='manager';
 
 EXPLAIN SELECT * FROM employees_copy WHERE name in ('LiLei','HanMeimei','Lucy') AND age = 22 AND position ='manager';

在这里插入图片描述
在这里插入图片描述

5、 like KK% 一般情况都会走索引

  EXPLAIN SELECT * FROM employees WHERE name like 'LiLei%' AND age = 22 AND position ='manager';

在这里插入图片描述

	EXPLAIN SELECT * FROM employees_copy WHERE name like 'LiLei%' AND age = 22 AND position ='manager';

在这里插入图片描述

索引下推(Index Condition Pushdown,ICP)

like KK%其实就是用到了索引下推优化
对于辅助的联合索引(name,age,position),正常情况按照最左前缀原则,SELECT * FROM employees WHERE name like ‘LiLei%’ AND age = 22 AND position =‘manager’ 这种情况只会走name字段索引,因为根据name字段过滤完,得到的索引行里的 age 和 position是无序的,无法很好的利用索引。在MySQL5.6之前版本,这个查询只能在联合索引里匹配名字是 ‘LiLei’ 开头的索引,然后拿这些索引对应主键逐个回表,到主键索引上找出相应的记录,再比对age和position这两个字段的值是否符合。MySQL 5.6引入了索引下推优化可以在索引遍历过程中,对索引中包含的所有字段先做判断过滤掉不符合条件记录之后再回表,可以有效的减少回表次数使用了索引下推优化后,上面那个查询在联合索引里匹配名字是 ‘LiLei’ 开头的索引之后,同时还会在索引里过滤age和position这两个字段,拿着过滤完剩下的索引对应主键id再回表查整行数据。
索引下推会减少回表次数,对于innodb引擎的表索引下推只能用于二级索引innodb主键索引(聚簇索引)树叶子节点保存的是全行数据,所以这个时候索引下推并不会起到减少查询行数据的效果

为什么范围查找MySQL没有用索引下推优化

估计应该是Mysql认为范围查找过滤结果集过大,like KK% 在绝大多数情况来看,过滤后的结果比较小,所以这里MySQL选择给 like KK% 用了索引下推优化,当然这也不是绝对的,有时like KK% 也不一定就会走索引下推。

MySQL如何选择合适的索引

EXPLAIN select * from employees where name > 'a';

没走索引
在这里插入图片描述

EXPLAIN select * from employees where name > 'zzz';
 

走了索引
在这里插入图片描述
MySQL会计算走索引和不走索引的成本,如果走索引会看走那个索引花费的成本小。

trace工具用法

set session optimizer_trace="enabled=on",end_markers_in_json=on; ‐‐开启trace
select * from employees where name > 'a' order by position;
SELECT * FROM information_schema.OPTIMIZER_TRACE;

常见sql深入优化

order by 与group by 优化
在这里插入图片描述
上图用了索引,如果Extra中用了Using filesort就是没有用索引

case 8:
数据量大所以走了全表扫描
在这里插入图片描述
可以使用覆盖索引优化
在这里插入图片描述

优化总结

1、MySQL支持两种方式排序indexfilesort,Using index MySQL扫描索引本身完成排序,效率高,filesort效率低。
2、order by 会使用Using index的两种情况:

Using filesort文件排序原理详解

filesort文件排序方式【单路排序、双路排序(回表)】

MySQL通过比较系统变量max_length_for_sort_data默认1024字节)的大小需要查询的字段总大小判断使用那种模式

explain select * from employee where name = ‘tqqorder by  position

单路排序详细过程
1、从索引name找到第一个满足name=‘tqq条件主键id;
2、根据主键id取出整行取出所有字段的值,存入sort Buffer中
3、从索引name找到下一个满足name = ‘tqq’条件主键id;
4、重复步骤2、3直到不满足name=‘tqq’
5、对sort buffer 中的数据按照字段position进行排序
6、返回结果客户端

双路排序详细过程
1、从索引name找到第一个满足name=‘tqq’ 条件的主键id;
2、根据主键id取出整行,把排序字段position和主键id两个字段放到sort buffer
3、从索引name取出下一个满足name = ‘tqq’记录的主键
4、重复步骤2、3直到不满足name=‘tqq’
5、对sort buffer中的字段position和主键id按照字段position进行排序
6、遍历排序好的id和字段position,按照id的值回到原表中取出所有字段返回客户端

索引的设计原则

1、代码先行,索引后上
业务主体功能开发完毕,把设计到该表相关的SQL拿出来分析之后再建立索引。
2、联合索引尽量覆盖条件
尽量少建单值索引。可以设计1-3个联合索引,让每一个联合索引都尽量去包含SQL语句里的where、order by 、group by 的字段,联合索引的字段顺序尽量满足SQL查询的最左前缀原则
3、不要在小基数字段上建立索引
索引基数就是这个字段在表中总共有多少个不同的值。比如性别。
4、长字符串我们可以采用前缀索引
对于varchar(255)的大字段可能会比较占用磁盘空间,可以对字段的前20个字符建立索引,对这个字段里的每个值的前20个字符放在索引树中,类似key index(name(20),age,position),这样就不能使用order by 了
5、where与order by 冲突时候优先where
一般这种时候往往都是让where条件去使用索引快速搜索出来一部分指定数据,接着再进行排序。因为大多数情况基于索引进行where筛选往往可以最快速筛选出你想要的数据然后排序的成本可能会小很多
6、基于慢SQL查询做优化
可以根据监控后台的一些慢SQL,针对慢SQL查询做特定的索引优化
慢SQL查询:https://blog.csdn.net/qq_40884473/article/details/89455740

设计索引的核心思想是:尽量利用一两个复杂的多字段联合索引,抗下80%以上的查询,然后用一两个辅助索引尽量抗下剩余的一些非典型查询。保证大数据量表的查询尽可能多的都能充分利用索引,这样就能保证查询速读和性能了。

原文地址:https://blog.csdn.net/weixin_42072357/article/details/134621736

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_27968.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注