面对 MySQL 查询索引失效,程序员的六大优化技巧!( 二 )

  • CBO---Cost_Based Potimizer 基于成本的优化器:CBO在会从目标诸多的执行路径中选择一个成本最小的执行路径来作为执行计划 。这里的成本他实际代表了MySQL根据相关统计信息计算出来目标SQL对应的步骤的IO , CPU等消耗 。也就是意味着数据库里的成本实际上就是对于执行目标SQL所需要IO,CPU等资源的一个估计值 。而成本值是根据索引 , 表 , 行的统计信息计算出来的(计算过程比较复杂) 。
  • 第五步执行器:开始执行的时候 , 首先会判断此次连接是否有对应的操作权限 , 如果没有 , 则返回没有权限的错误 。如果有权限 , 则打开表继续执行 。打开表的时候 , 执行器会根据表的引擎定义 , 去使用这个引擎提供的接口 。
    比如下面这条sql语句执行器流程是这样的:
    select* fromt_test3 wherename= 'a';
    1. 调用InnoDB引擎接口获取这个表的第一行 , 判断name的值是不是a , 如果不是则跳过 , 如果是则将这行存在结果集中 。
    2. 调用引擎接口获取下一行 , 重复相应的判断逻辑 , 直到取到最后一行数据
    3. 执行器将遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端 。
    通过了解sql执行的过程以及优化器 , 发现mysql采用的是第二种基于成本的优化器 , 它会根据sql执行的成本选择合适的路径 。所以可以推断出上面sql执行计划没有采用对应列的索引原因 。当我在表中插入一万条数据的时候 , 再重新查看对应的执行计划时 , 发现此时 , 该sql的查询类型会使用range类型及使用name对应的索引进行查询 。
    当数据量比较小的时候 , 会使用all类型进行查询对应数据 , 当数据量比较大时 , 查询数据量增大时 , 会采用range类型 , 并使用对应列的索引进行查询 。这便涉及到了数据库查询索引的离散度 。离散度 , 外文 Measures of Dispersion , 是指通过随机地观测变量各个取值之间的差异程度 , 用来衡量风险大小的指标 。离散度在不超过全表的10%-15%的前提下索引才可以显示索引所具有的价值 。当离散度超过该值的情况下全表扫描可能反倒比索引扫描更有效 。我们所追求的目标就是创建全表扫描所无法比拟的有效索引 。比如当我们对一张学生表信息中对性别添加索引 , 性别只有两种值 , 会产生大量的重复 , 离散度较小 , 使用性别索引会增加查询开销 , 使得在使用性别的索引查询时可能比没有性别索引的查询更慢 。
    基于数据库索引的离散度 , 可以参考以下两个建议进行创建索引:
    • 在允许的情况下 , 对具有较好离散度的列单独创建索引 , 这样可以提高该索引的使用弹性;
    • 对于离散度较差的列 , 通过对多列进行合理的组合来创建组合索引 , 虽然这样做在很大程度上降低了各个列的使用弹性 , 但是却可以发挥多个列的综合效应 。
    在实际应用的过程中 , MySQL索引失效的情形很多 。例如:在WHERE条件的LIKE关键字匹配的字符串以”%“开头 , 这种情况下 , 索引是不会起到作用的;WHERE条件中使用OR关键字来连接多个查询条件 , 如果有一个条件没有使用索引 , 那么其他的索引也不会起作用;多列索引的第一个字段没有使用 , 那么这个多列索引也不会起作用 。使用in查询时 , in查询条件超过数据库表的一半的时候也会失效 。
    【面对 MySQL 查询索引失效,程序员的六大优化技巧!】根据这些情况 , 我们必须选择对索引有正确的理解 , 并不是创建索引就能增加查询速度 。根据使用索引的特性 , 对创建索引的一些技巧总结如下:
    1. 首先数据量小的表不需要建立索引 , 因为数据量小的表即使建立索引也不会有大的用处 , 还会增加额外的索引开销。
    2. 不经常引用的列不要建立索引 , 因为不常用 , 即使建立了索引也没有多大意义。
    3. 经常频繁更新的列不要建立索引 , 因为肯定会影响插入或更新的效率。
    4. 尽量避免在 where 子句中使用 ! = 或者 <> 操作符 , 查询引用会放弃索引而进行全表扫描 。


      推荐阅读