跳转到内容

MySql索引优化

索引的类型

下面将MySQL支持的索引类型进行简单的总结:

  • B-Tree索引

    最常见的索引类型,支持大部分存储引擎。

  • B+Tree索引

    在B-Tree索引的基础上进行优化的结果,在MySQL中大部分存储引擎都支持B+Tree索引。如果没有为数据库或数据表显示地指定索引类型,则MySQL底层会默认使用B+Tree索引。

  • Hash索引

    比较适合存储Key-Value型数据。查询Key-Value型数据时,会根据Key快速获取数据。但是Hash索引有个弊端,即不适合根据某个数据范围来查询数据。

  • R-Tree索引

    空间索引,对于地理空间类型的数据来说,通常会使用R-Tree索引。

  • Full-Text索引

    主要用于全文检索。在MySQL5.6版本之前,Full-Text索引只支持MyISAM存储引擎。从MySQL5.6开始,InnoDB存储引擎开始支持Full-Text索引。

使用索引的场景

  1. 全值匹配

    全值匹配是指在MySQL的查询条件中包含索引中所有列,并且针对索引中的每列进行等值判断。

  2. 查询范围

    MySQL支持对索引的值进行范围查找。

  3. 匹配最左原则

    在使用联合索引查询数据时从联合索引中的最左边的列开始查询,并且不能跳过索引中的列。如果跳过索引中的列查询数据,则在后续的查询中将不再使用索引。

  4. 查询索引列

    在查询包含索引的列或者查询的列都在索引中时,查询的效率比使用SELECT *或者查询没有索引的列的效率要高很多。

  5. 匹配字段前缀

    如果数据表中的字段存储的数据比较长,则在整个字段上添加索引会影响数据的写入性能,增加MySQL维护索引的负担。此时,可以在字段的开头部分添加索引,并按照此索引进行数据查询。

  6. 精确与范围匹配索引

    在查询数据时,可以同时精确匹配索引并按照另一个索引的范围进行数据查询。

  7. 匹配NULL值

    对一个添加了索引的字段判断是否为NULL时会使用到索引进行查询。

  8. 连接查询匹配索引

    使用JOIN连接语句查询多个数据表中的数据,并且当实现JOIN连接的字段上添加了索引时,MySQL会使用索引进行查询数据。

  9. LIKE匹配索引

    当like语句中的查询条件不以通配符开始时,MySQL会使用索引查询数据。

索引失效的场景

  1. 以通配符开的LIKE语句

    当使用以通配符开始的LIKE语句查询时,MySQL不会使用索引。

  2. 数据类型转换

    当查询的字段数据进行了数据类型转换时,MySQL不会使用索引查询数据。

  3. 联合索引未匹配最左原则

    当数据表中创建了联合索引,如果索引在查询数据时,查询条件不包含联合索引最左边的列或者最左边列的开发部分,即不满足最左前缀匹配规则,那么MySQL不会使用索引。

  4. OR语句

    查询语句中使用OR来连接多个查询条件时,只要查询条件中存在未创建索引的字段,MySQL就不会使用索引。

  5. 计算索引列

    查询数据时对查询条件的字段添加了索引,而且在查询数据时对字段进行了计算或者使用了函数,此时MySQL不会使用索引。

  6. 范围条件右侧的列无法使用索引

    使用联合索引查询数据时,如果按照联合索引中字段的某个范围查询数据,则此字段后面的列无法使用索引,会进行全表扫描。

  7. 使用<>或!=操作符匹配查询条件

    在MySQL中,使用使用<>或!=操作符匹配查询条件时不会使用索引。

  8. 匹配NOT NULL值

    在MySQL中使用IS NULL判断某个字段是否为NULL时,会使用该字段的索引。相反,如果使用NOT NULL 来验证某个字段不为NULL时,会进行全表扫描操作。

  9. 索引耗时

    在某些场景下,如果MySQL评估使用索引比使用全表扫描查询数据性能更低,则不会使用索引来查询数据,而会进行全表扫描。

优先考虑覆盖索引

理解1:索引是高效找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据;当能通过读取索引就可以得到想要的数 据,那就不需要读取行了。一个索引包含了满足查询结果的数据就叫做覆盖索引。

理解2:非聚簇复合索引的一种形式,它包括在查询里的SELECT、JOIN和WHERE子句用到的所有列 (即建索引的字段正好是覆盖查询条件中所涉及的字段)。

简单说就是, 索引列+主键包含 SELECT 到 FROM之间查询的列 。

覆盖索引的利弊

  • 好处

    1、避免Innodb表进行索引的二次查询(回表)

    2、可以把随机IO变成顺序IO加快查询效率

  • 弊端

    索引字段的维护 总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。

索引条件下推

Index Condition Pushdown(ICP)是MySQL 5.6中新特性,是一种在存储引擎层使用索引过滤数据的一种优化方式。ICP可以减少存储引擎访问基表的次数以及MySQL服务器访问存储引擎的次数。把本来由Server层做的索引条件检查下推给存储引擎层来做,以降低回表和访问存储引擎的次数,提高查询效率。

使用前后对比

  • 如果没有ICP,存储引擎会遍历索引以定位基表中的行,并将它们返回给MySQL服务器,由MySQL服务器评估WHERE后面的条件是否留行。

  • 启用ICP后,如果部分WHERE条件可以使用索引中的列进行筛选,则MySQL服务器会把这部分WHERE条件放到存储引擎筛选。然后,存储引擎通过使用索引条目来筛选数据,并且只有在满足这一条时才从表中读取行

    好处:ICP可以减少存储引擎必须访问基表的次数和MySQL服务器必须访问存储引擎的次数。但是,ICP的加速效果取决于存储引擎内通过ICP筛选掉的数据的比例。

MySQL默认开启索引条件下推,可以使用如下命令关闭:

SET optimizer_switch='index_condition_pushdown=off';

当使用索引条件下推时,EXPLAIN语句输出的结果中Extra列内容为 Using index condition

ICP的使用条件

  • 只能用于二级索引(secondary index)

  • explain显示的执行计划中type值(join 类型)为 range 、 ref 、 eq_ref 或者 ref_or_null

  • 并非全部where条件都可以用ICP筛选,如果where条件的字段不在索引列中,还是要读取整表的记录 到server端做where过滤

  • ICP可以用于MyISAM和InnnoDB存储引擎

  • MySQL 5.6版本的不支持分区表的ICP功能,5.7版本的开始支持

  • 当SQL使用覆盖索引时,不支持ICP优化方法