巅峰战队|详解一条查询select语句和更新update语句的执行流程( 三 )

  • 预估并转化为常数表达式
  • 覆盖索引扫描 。 想要详细了解覆盖索引的可以点击这里 。
  • 的查询优化 。
  • 提前终止查询 。 比如我们使用了一个不成立的条件 , 则会立刻返回空 。
  • 等值传播 。
  • 优化IN()语句 。 在其他很多数据库中in等同于or语句 , 但是MySQL中会讲in中的值先进行排序 , 然后按照二分查找的方法来确定是否满足条件 。
  • 实际当中优化器能做的优化远远比上面列举的更多 , 所以有时候我们不要觉得比优化器更聪明 , 所以大部分情况下我们都可以让优化器做出优化就可以了 , 如果有些我们确定优化器没有选择最优的查询方案 , 我们也可以在查询中通过添加hint提示告知到优化器 , 比如通过force index强制使用索引或者straight_join语句强制优化器按我们想要的表顺序进行关联 。
    优化器并不是万能的MySQL优化器也并不是万能的 , 并不是总能把我们写的糟糕的sql语句优化成一个高效的查询语句 , 而且也有很多种原因会导致优化器做出错误的选择:
    • 统计信息不准确 。 MySQL评估成本依赖于存储引擎提供的的统计信息 , 然而存储引擎提供的统计信息有时候会有较大偏差 。
    • 执行计划的成本估算不等于实际的执行成本 。 比如估算成本的时候不考虑缓存 , 而实际执行有些数据在缓存中 。
    • 优化器认为的最优可能并不是我们需要的最优 。 比如有时候我们想要时间最短 , 但是优化器
    • 优化器从不考虑其他并发的查询 。
    • 优化器并不总是基本成本的优化 。 有时候也会基于规则 , 比如当存在全文索引 , 查询时使用了match()子句时 , 即使选择其他索引更优 , 优化器仍然会选择全文索引 。
    • 优化器不将不受其控制的操作计算为成本 。 如执行存储过程或者用户自定义函数的成本 。
    • 优化器有时候无法估算所有的执行计划 , 所以也有可能错过最优执行计划 。
    优化器如何得到查询计划优化器听起来比较抽象 , 给人一种看不见摸不着的感觉 , 但是实际上我们也可以通过参数打开优化器追踪 , 优化器追踪默认是关闭的 , 因为开启后会影响性能 , 所以建议是在需要定位问题的时候开启 , 并及时关闭 。
    SHOW VARIABLES LIKE 'optimizer_trace';set optimizer_trace='enabled=on';接下来执行一句查询语句:
    SELECT t1.name AS name1,t2.name AS name2 FROM test t1 INNER JOIN test2 t2 ON t1.id=t2.id这时候优化器的分析过程已经被记录下来了 , 可以通过下面语句查询:
    SELECT * FROM information_schema.optimizer_trace;得到如下结果:
    巅峰战队|详解一条查询select语句和更新update语句的执行流程上面的图是为了看数据效果 , 如果需要自己操作的话 , 需要用shelll命令窗口去执行 , sqlyog工具中直接查询出来TRACE列是空的 , shell中返回的TRACE列信息如下:
    巅峰战队|详解一条查询select语句和更新update语句的执行流程从截图中的轮廓可以看出来这是一个json数据格式 。
    跟踪信息主要分为以下三部分(上图并未将全部内容展示出来 , 感兴趣的可以自己去尝试一下 , 开启之后记得及时关闭哦):
    • 准备阶段(join_preparation):expanded_query中的查询语句就是优化后的sql
    • 优化阶段(join_optimization):considered_execution_plans中列出来所有的执行计划
    • 执行阶段(join_execution)
    存储引擎查询当Server层得到了一条sql语句的执行计划后 , 这时候就会去调用存储引擎层对应的API , 执行查询了 。 因为MySQL的存储引擎是插件式的 , 所以每种存储引擎都会对Server提供了一些对应的API调用 。