zoukankan      html  css  js  c++  java
  • MySQL 查询优化

    1. 关联查询执行流程

    MySQL执行关联查询的策略很简单,他会从一个表中循环取出单条数据,然后用该条数据到下一个表中寻找匹配的行,然后回溯到上一个表,到所有的数据匹配完成为止。因此也被称为“嵌套循环关联”。

    来看下面这个SQL:

    select tb1.col1, tb2,col2
      from tb1 inner join tb2 using(col3)
      where tb1.col1 in (5,6)
    

    他的执行顺序为(伪代码):

    List outerDataList = "select * from tb1 where col1 in (5,6)"
      for(outerData in outerDataList){
        List innerDataList = "select * from tb2 where col3 = outerData.col3"
          for(innerData : innerDataList){
            output(outterData,innerData)
          }
      }
    

    MySQL认为所有的查询都是一次关联查询,所以如果查询一个表,上述过程也适合,不过只需要完成上面外层的基本操作。

    再来看看left outter join查询的过程,SQL如下:

    select tb1.col1, tb2,col2
    from tb1 left outer join tb2 using(col3)
    where tb1.col1 in (5,6)
    

    伪代码如下:

    List outerDataList = "select * from tb1 where col1 in (5,6)"
      for(outerData in outerDataList){
        List innerDataList = "select * from tb2 where col3 = outerData.col3"
          if(innerDataList != null){
            for(innerData : innerDataList){
              output(outterData,innerData)
            }
          }else{
            // inner表无对应数据,以outter数据为准
            output(outterData,null)
          }
      }
    

    但是这种遍历的查询方式不能满足所有的联合查询,比如“全外连接”查询(full outer join)不能使用该方法来实现,这可能是MySQL不支持全外接查询的原因 ~~~

    2. 优化

    MySQL会将查询命令生成一颗指令树,比如四表联合查询的指令树如下:

    MySQL在生成指令树之前会先对SQL语句的执行效率进行评估,然后选择他认为效率最高的关联顺序执行。对于如下SQL:

    EXPLAIN SELECT
    	actor.NAME,
    	film.title 
    FROM
    	actor actor
    	INNER JOIN film_actor USING ( actor_id )
    	INNER JOIN film USING ( film_id )
    

    从执行计划可以看出,MySQL选择将film作为第一个关联表,拿到数据后再依次扫描film_actor、actor表取数据。MySQL的选择策略是,尽量让查询执行更少的嵌套循环和回溯操作,因此,他会尽量将外层查询的数据量更少。因为film表只有4条记录,actor表有6条记录,因此他认为选择将film作为第一个表开始查询有更高的执行效率。

    但是MySQL的优化策略会比这复杂的多,MySQL会计算所有执行顺序的代价,然后选择他认为的最佳执行计划。但是,如果联合查询的表比较多,他不一定能穷举所有的执行情况选择最佳的执行策略,所以这种默认的优化方式却不一定总是最佳的。还是以上条SQL为例子,假设在film表的film_id字段上建立了索引,那么即使film上的字段少于actor,可能使用actor表作为第一个表进行查询,效率会更高(里层嵌套查询film表数据时可以使用索引)。如果你认为有更佳的执行顺序,可以使用STRAIGHT_JOIN关键字强行执行查询顺序:

    EXPLAIN SELECT
    	actor.NAME,
    	film.title 
    FROM
    	actor actor
    	STRAIGHT_JOIN film_actor USING ( actor_id )
    	STRAIGHT_JOIN film USING ( film_id )
    

    注意:绝大多数时候,MySQL做出的判断都比人类要准确,绝大多数时候,不推荐强制执行顺序。

  • 相关阅读:
    C#学习笔记_01_基础内容
    C#学习笔记_03_运算符
    C#学习笔记_02_数据类型
    统计学习方法(一)
    《史蒂夫·乔布斯传》读书笔记
    《孵化twitter》读书笔记
    保存和恢复 Android Fragment 的状态
    计算机视觉中的边缘检测
    Android开发的过去、现在和将来
    Python常用的第三方库
  • 原文地址:https://www.cnblogs.com/moongeek/p/11332504.html
Copyright © 2011-2022 走看看