索引优化实战
2023-01-08 16:49:40 7 举报
AI智能生成
学习
作者其他创作
大纲/内容
按表条件过滤的行百分比
fitered
表示表的连接类型
type
常用的类型有: ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行index: Full Index Scan,index与ALL区别为index类型只遍历索引树range:只检索给定范围的行,使用一个索引来选择行ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用systemNULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
匹配的分区
partitions
表示查询时可能使用的索引
possible_keys
指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用(该查询可以利用的索引,如果没有任何索引显示 null)该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询
表示实际使用的索引
key
key列显示MySQL实际决定使用的键(索引),必然包含在possible_keys中如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
索引字段的长度
key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)不损失精确性的情况下,长度越短越好
执行情况的描述和说明
extra
Using where:不用读取表中所有信息,仅通过索引就可以获取所需数据,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询,常见 group by ; order byUsing filesort:当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”Using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。Impossible where:这个值强调了where语句会导致没有符合条件的行(通过收集统计信息不可能存在结果)。Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行No tables used:Query语句中使用from dual 或不含任何from子句
列与索引的比较
ref
列与索引的比较,表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
输出结果集的表
table
在表有别名的情况下,会展示别名
选择标识符
id
1. id相同时,执行顺序由上至下2. 如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行3. id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行
表示查询的类型
select_type
扫描出的行数(估算的行数)
rows
估算出结果集行数,表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数
总结:• EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况• EXPLAIN不考虑各种Cache• EXPLAIN不能显示MySQL在执行查询时所作的优化工作• 部分统计信息是估算的,并非精确值• EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。
总结
explain
主要针对于普通索引(二级索引),查询结果包含除索引外的其他列,需要经过普通索引查找到主键值,然后再根据主键查找才能返回结果(二次查找)
回表
查询结果只包含主键列以及查询条件中所使用的其他索引列,再经过一次的索引查询后就可以返回结果,避免了回表查询
不同的存储实现覆盖索引的方式不同,不是所有的引擎都支持覆盖索引,memory不支持覆盖索引;因为innodb是基于聚簇索引的,所以覆盖索引的效果极好
覆盖索引
针对于组合索引,在使用中只会先从组合索引列的最左边列开始进行列匹配,匹配不成功,索引失效(有一才有二,有二才有三...)
最左匹配
在数据返回server端前,执行引擎就完成了对所有索引列数据的匹配过滤,将过滤后的数据再返回server端,减少了返回的数据条数,减少了io次数
索引下推
相关名词
explain select * from menu where menu_id+1=5; -- 主键索引失效
explain select * from menu where menu_id=4; -- 使用索引查询
1、当使用索引列进行查询的时候尽量不要使用表达式,把计算放到业务层而不是数据库层
2、尽量使用主键查询,而不是其他索引,因为主键查询不会触发回表查询
当频繁进行查询操作的列数据较长时,可截取该列的不重复的前n长度建立索引进行查询,以避免在整个字段建立索引较为消耗资源
计算city字段的前n个长度的不重复值dv(distinct value),选择dv基本不变的n值建立索引
1.通过计算完整列的选择性,来选择合适的长度建立索引
alter table emp add index idx_city_dv(city(7));
2.创建前缀索引
3、使用前缀索引
索引的建立最好能兼顾查询和排序,这样可最大程度的利用索引
如果排序列可以和条件查询列组成最左前缀索引,会大大提高查询的效率(查询条件要先匹配左才能生效)
查询和排序组合成最左前缀时,排序中字段的升降也要保持一样(同asc同desc),两者兼顾也会进行全表扫描,导致索引失效
查询中没有使用到索引,即使排序字段使用了索引也不会生效(会进行全表的扫描,explain中的Extra列会出现Using filesort)
4、使用索引扫描来排序
查询相同的情况下,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=3select * 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 查询结果返回四条数据
5、union all,in,or都能够使用索引,但是推荐使用in
>,<,范围列可以使用索引,但是范围列后面的列无法用到索引,索引最多用于一个范围列
范围查询中使用一般索引可能会失效:在sql语句执行前,会通过分析器优化器进行sql的分析优化,当发现使用索引的效率要远大于不使用索引时,索引才会生效
6、范围查询可以使用到索引
为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,使用索引
7、强制类型转换可能会导致索引失效进行全表扫描
更新会变更B+树,更新频繁的字段建索引会大大降低数据库性能
类似于性别这类区分不大的属性,建立索引是没有意义的,不能有效的过滤数据
一般区分度在80%以上的时候就可以建立索引,区分度可以使用 count(distinct(列名))/count(*) 来计算
8、更新十分频繁,或者数据区分度不高的字段上不宜建立索引
当需要进行表连接的时候,最好不要超过三张表,需要join的字段,数据类型必须一致(出自alibaba开发手册)
join时遵循小表join大表的原则(系统优化后不一定会是书写sql的顺序)
尽量使用关联查询来替代子查询(子查询会产生较大的临时表)
简单嵌套循环连接算法
连接表的个数相当于嵌套循环的层数,每次从一个循环中的第一个表中读取一行,然后将每一行传递给一个嵌套循环,该循环处理联接中的下一个表。
重复此过程的次数与要连接的表的次数相同。
因为NLJ算法从外循环到内循环一次传递一行,所以它通常会多次读取在内循环中处理的表
Simple Nested-Loop Join Algorithm
索引嵌套循环连接算法
要求非驱动表的连接列有索引,可以通过索引来较少比较,加速查询
在查询时,驱动表会根据关联字段的索引进行查找,根据索引找到符合的值时,在进行回表查找(只有当匹配到索引才进行回表查询)
如果非驱动表的关联字段是主键,性能会更高;如果不是主键,则要再进行回表查询,性能会比主键索引较低一些
Index 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
Block Nested-Loop Join Algorithm
9、join连接使用
创建索引的列,不允许为null,为null时可能会得到不符合预期的结果(非强制)
能用limit的要尽量使用limit
索引并不是越多越好,单个表中索引建议控制在5个以内;组合索引字段数不允许超过5个
10、其他
优化细节
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 > 'Mary';
可以查找某一个范围的数据
匹配范围值
explain select * from staffs where name = 'July' and age > 25;
可以查询第一列的全部和第二列的部分
精确匹配某一列并范围匹配另外一列
查询的时候只需要访问索引,不需要访问数据行,本质上就是覆盖索引
只访问索引的查询
注:staffs包含主键索引id,以及组合索引(name,age,pos)
索引匹配方式
索引优化实战
0 条评论
下一页