索引优化实战
2023-01-08 16:49:40 7 举报
AI智能生成
学习
作者其他创作
大纲/内容
explain
fitered
按表条件过滤的行百分比
type
表示表的连接类型
partitions
匹配的分区
possible_keys
表示查询时可能使用的索引
key
表示实际使用的索引
key_len
索引字段的长度
extra
执行情况的描述和说明
ref
列与索引的比较
table
输出结果集的表
id
选择标识符
select_type
表示查询的类型
rows
扫描出的行数(估算的行数)
总结
总结:
• EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
• EXPLAIN不考虑各种Cache
• EXPLAIN不能显示MySQL在执行查询时所作的优化工作
• 部分统计信息是估算的,并非精确值
• EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。
• EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
• EXPLAIN不考虑各种Cache
• EXPLAIN不能显示MySQL在执行查询时所作的优化工作
• 部分统计信息是估算的,并非精确值
• EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。
相关名词
回表
主要针对于普通索引(二级索引),查询结果包含除索引外的其他列,需要经过普通索引查找到主键值,然后再根据主键查找才能返回结果(二次查找)
覆盖索引
查询结果只包含主键列以及查询条件中所使用的其他索引列,再经过一次的索引查询后就可以返回结果,避免了回表查询
不同的存储实现覆盖索引的方式不同,不是所有的引擎都支持覆盖索引,memory不支持覆盖索引;因为innodb是基于聚簇索引的,所以覆盖索引的效果极好
eg:select sname,sid from sort where sname = 'XX'; --(sname列已添加索引)覆盖索引,查询语句前添加explain进行查看extra列中显示为Using index
最左匹配
针对于组合索引,在使用中只会先从组合索引列的最左边列开始进行列匹配,匹配不成功,索引失效(有一才有二,有二才有三...)
索引下推
在数据返回server端前,执行引擎就完成了对所有索引列数据的匹配过滤,将过滤后的数据再返回server端,减少了返回的数据条数,减少了io次数
优化细节
1、当使用索引列进行查询的时候尽量不要使用表达式,把计算放到业务层而不是数据库层
explain select * from menu where menu_id+1=5; -- 主键索引失效
explain select * from menu where menu_id=4; -- 使用索引查询
2、尽量使用主键查询,而不是其他索引,因为主键查询不会触发回表查询
3、使用前缀索引
当频繁进行查询操作的列数据较长时,可截取该列的不重复的前n长度建立索引进行查询,以避免在整个字段建立索引较为消耗资源
1.通过计算完整列的选择性,来选择合适的长度建立索引
select count(distinct left(city,3))/count(*) as sel3 from emp
计算city字段的前n个长度的不重复值dv(distinct value),选择dv基本不变的n值建立索引
2.创建前缀索引
alter table emp add index idx_city_dv(city(7));
4、使用索引扫描来排序
索引的建立最好能兼顾查询和排序,这样可最大程度的利用索引
如果排序列可以和条件查询列组成最左前缀索引,会大大提高查询的效率(查询条件要先匹配左才能生效)
查询和排序组合成最左前缀时,排序中字段的升降也要保持一样(同asc同desc),两者兼顾也会进行全表扫描,导致索引失效
查询中没有使用到索引,即使排序字段使用了索引也不会生效(会进行全表的扫描,explain中的Extra列会出现Using filesort)
5、union all,in,or都能够使用索引,但是推荐使用in
查询相同的情况下,union all 实际是进行了两次查询,in和or都是一次查询,但是in的效率要比or的效率高
union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序
union all:对两个结果集进行并集操作,包括重复行,不进行排序(效率比union高)
select * from menu where menu_id=1 or menu_id=2 union all select * from menu where menu_id=1 or menu_id=3
select * from menu where menu_id=1 or menu_id=2 union select * from menu where menu_id=1 or menu_id=3
select * from menu where menu_id=1 or menu_id=2 union select * from menu where menu_id=1 or menu_id=3
上述查询,如果查询的id列都存在,union查询结果返回三条数据,union all 查询结果返回四条数据
6、范围查询可以使用到索引
>,<,范围列可以使用索引,但是范围列后面的列无法用到索引,索引最多用于一个范围列
范围查询中使用一般索引可能会失效:在sql语句执行前,会通过分析器优化器进行sql的分析优化,当发现使用索引的效率要远大于不使用索引时,索引才会生效
7、强制类型转换可能会导致索引失效进行全表扫描
为emp表的tel添加索引:alter table emp add index idx_tel(tel);
explain select * from emp where tel=15738967250; -- type=all,索引失效,进行全表扫描
explain select * from emp where tel='15738967250'; -- type=ref,使用索引
8、更新十分频繁,或者数据区分度不高的字段上不宜建立索引
更新会变更B+树,更新频繁的字段建索引会大大降低数据库性能
类似于性别这类区分不大的属性,建立索引是没有意义的,不能有效的过滤数据
一般区分度在80%以上的时候就可以建立索引,区分度可以使用 count(distinct(列名))/count(*) 来计算
9、join连接使用
当需要进行表连接的时候,最好不要超过三张表,需要join的字段,数据类型必须一致(出自alibaba开发手册)
join时遵循小表join大表的原则(系统优化后不一定会是书写sql的顺序)
尽量使用关联查询来替代子查询(子查询会产生较大的临时表)
Simple Nested-Loop Join Algorithm
简单嵌套循环连接算法
连接表的个数相当于嵌套循环的层数,每次从一个循环中的第一个表中读取一行,然后将每一行传递给一个嵌套循环,该循环处理联接中的下一个表。
重复此过程的次数与要连接的表的次数相同。
因为NLJ算法从外循环到内循环一次传递一行,所以它通常会多次读取在内循环中处理的表
Index Nested-Loop Join Algorithm
索引嵌套循环连接算法
要求非驱动表的连接列有索引,可以通过索引来较少比较,加速查询
在查询时,驱动表会根据关联字段的索引进行查找,根据索引找到符合的值时,在进行回表查找(只有当匹配到索引才进行回表查询)
如果非驱动表的关联字段是主键,性能会更高;如果不是主键,则要再进行回表查询,性能会比主键索引较低一些
Block Nested-Loop Join Algorithm
块嵌套循环连接算法
如果有索引会采用Index Nested-Loop Join Algorithm,如果没有索引会采用Block Nested-Loop Join Algorithm
该连接方式在每两个表之间会有一个join-buffer缓冲区,会将驱动表的所有关联列以及查询需要的结果列先缓存到join buffer中
然后再用join buffer中的行数据批量与非驱动表进行匹配,将第一种的每次循环匹配合并为一次匹配,降低了非驱动表的访问
join_buffer_size系统默认值是256K,可以自定义参数大小;N个表进行关联查询时,会产生N-1个buffer
10、其他
创建索引的列,不允许为null,为null时可能会得到不符合预期的结果(非强制)
能用limit的要尽量使用limit
索引并不是越多越好,单个表中索引建议控制在5个以内;组合索引字段数不允许超过5个
索引匹配方式
全值匹配
全值匹配指的是和索引中的所有列进行匹配
explain select * from staffs where name = 'July' and age = 23 and pos = 'dev';
匹配最左前缀
只匹配前面的几列
explain select * from staffs where name = 'July' and age = 23;
explain select * from staffs where name = 'July';
匹配列前缀
可以匹配某一列的值的开头部分
explain select * from staffs where name like 'J%'; -- type=range,Extra=Using index condition
explain select * from staffs where name like '%y'; --索引失效, type=all,Extra=Using where
匹配范围值
可以查找某一个范围的数据
explain select * from staffs where name > 'Mary';
精确匹配某一列并范围匹配另外一列
可以查询第一列的全部和第二列的部分
explain select * from staffs where name = 'July' and age > 25;
只访问索引的查询
查询的时候只需要访问索引,不需要访问数据行,本质上就是覆盖索引
explain select name,age,pos from staffs where name = 'July' and age = 25 and pos = 'dev';
注:staffs包含主键索引id,以及组合索引(name,age,pos)
0 条评论
下一页