MySQL的索引优化与失效


JAVA后端开发知识总结(持续更新…)


MySQL的索引优化与失效


文章目录

  • MySQL的索引优化与失效
    • 单表索引优化及失效
    • 多表关联查询优化
    • 排序分组优化
    • Group by 和 Order by
    • exists / in 的优化
    • MySQL多条件查询索引为什么只用到一个


单表索引优化及失效

  • 通常,适合创建索引的列是出现在 WHERE 或 ON子句中的列,而不是出现在 SELECT 关键字后的列。
  • 尽量多地创建联合索引,而非单值索引。如果一个表的字段过多,索引过多,那么索引占用的空间也很多,在修改索引时,耗费的时间也较多。
  • 联合索引遵循 最佳左前缀法则

CREATE INDEX idx_age_deptId ON tab(age, deptId, NAME)

  像上例,如果索引了多列,要遵循最佳左前缀法则,即查询从索引的最左前列(顺序是索引建立时的顺序)开始并且不跳过索引中的列。即,当查询的条件为age 、(age, deptId)、(age, deptId, NAME)时,索引才生效。一旦不从age开始,或者跳过deptId,那么索引后面的字段都无法被使用,这是B+树的原理所决定的

  但是,查询的时候如果所有条件都用上了,但是顺序不同,查询引擎会自动优化,保证能够命中索引。在创建联合索引时,尽量把查询最频繁的那个字段作为最左(第一个)字段,查询的时候也尽量以这个字段为第一条件。

  • 联合索引及多列索引
  • 利用索引中的附加列,可以缩小搜索的范围,但使用一个具有两列的索引不同于使用两个单独的索引。
  • 复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序:
    如果知道姓,电话簿将非常有用;
    如果知道姓和名,电话簿则更为有用;
    但如果只知道名不知道姓,电话簿将没有用处。
  • 联合索引原理

《联合索引在B+Tree上的存储结构及数据查找方式》

MySQL的索引优化与失效_第1张图片

  • 条件字段加函数或者数学运算会导致索引失效。
  • 范围查询(比如>、<、or)索引时,索引右边的条件会失效。
  • 不等于(<>)会使索引失效。
  • IS NULL不会使索引失效,IS NOT NULL会使得索引失效。
  • LIKE以%开头会导致索引失效。

SELECT … FROM … WHERE name LIKE ‘%aa%’

  • 字段类型不匹配会导致索引优化失效。

总结

MySQL的索引优化与失效_第2张图片

多表关联查询优化

  • 对于左连接,由于主表为驱动表,无法避免全盘扫描,所以被驱动表中加入索引才有用,驱动表加索引就不会有效果。

MySQL的索引优化与失效_第3张图片

  • 对于内连接,不存在主表,此时系统将会自动优化,把有索引的表作为非驱动表。此外,遵循小表驱动大表的原则。
  • 对于直连STRAIGHT_JOIN:直接指定驱动表和被驱动表。
  • 虚拟表无法创建索引,最好放在驱动表位置上。
  • 少用子查询,会多一趟。
  • 如果必须用子查询,尽量不使用not in、not exists、not null,用left join on + is null 代替。

总结

MySQL的索引优化与失效_第4张图片

排序分组优化

  • 判断是否用上索引,可以分析Exlain的最后一个字段ExtraORDER BY子句尽量使用INDEX方式排序,避免使用FileSort方式。
  • 对于排序语句,必须加过滤条件(LIMIT也行)才能生效。
  • ORDER BY后面的顺序与索引顺序不同,就会失效。
  • WHERE条件索引失效同样会导致ORDER BY后面的索引失效。
  • 多个字段分组时,升降序必须保持一致。
  • 范围查找索引时,右边的失效,包括ORDER BY。
  • Group by 与ORDER BY 差不多,只是无过滤条件时,依然可以索引。

Group by 和 Order by

《order by 和 group by 的区别》

  • order by 默认为升序,后面必须列出排序的字段名,可以是多个字段名。

  • group by 必须有聚合函数来配合才能使用,使用时至少需要一个分组标志字段。

exists / in 的优化

《常见Mysql的慢查询优化方式》

  • select * from a where id in (select id from b );

  MySQL会把in子查询转换成exists相关子查询,所以它实际等同于这条sql语句:select * from a where exists(select * from b where b.id=a.id );

  exists相关子查询的执行原理是:循环取出a表的每一条记录与b表进行比较,比较的条件是a.id=b.id,看a表的每条记录的id是否在b表存在,如果存在就行返回a表的这条记录,顺序是固定的

  • 但是由于顺序固定,a表(外表)使用不了索引,必须全表扫描,建索引只能在b表的id字段建。
  • 采用 inner join不让顺序固定,让数据库自己去处理,此时就可以A、B表都建索引

MySQL多条件查询索引为什么只用到一个

  • select count(1) from table1 where column1 = 1 and column2 = ‘foo’ and column3 = ‘bar’
  • 查询优化器不会都执行一遍,贪婪算法(最近邻居算法)不允许这种情况的发生,所以当遇到以上语句的时候,数据库只要用到第一个筛选列的索引(column1),就会直接去进行表扫描了。
  • 与其说是数据库只支持一条查询语句只使用一个索引,倒不如说N条独立索引同时在一条语句使用的消耗比只使用一个索引还要慢。

你可能感兴趣的:(MySQL,JAVA后端,mysql,索引,数据库)