zoukankan      html  css  js  c++  java
  • MYSQL ORDER BY Optimization

     ORDER BY Optimization

           某些情况下,MYSQL可以使用index排序而避免额外的sorting.

           即使order by语句列不能准确的匹配index,只要没有index中(不在order by的列)在where语句以常量形式出现。(最左前缀

    SELECT * FROM t1
      ORDER BY key_part1,key_part2,... ;
    
    SELECT * FROM t1
      WHERE key_part1 = constant
      ORDER BY key_part2;
    
    SELECT * FROM t1
      ORDER BY key_part1 DESC, key_part2 DESC;
    
    SELECT * FROM t1
      WHERE key_part1 = 1
      ORDER BY key_part1 DESC, key_part2 DESC;
    
    SELECT * FROM t1
      WHERE key_part1 > constant
      ORDER BY key_part1 ASC;
    
    SELECT * FROM t1
      WHERE key_part1 < constant
      ORDER BY key_part1 DESC;
    
    SELECT * FROM t1
      WHERE key_part1 = constant1 AND key_part2 > constant2
      ORDER BY key_part2;

           某些情况下,依旧使用Index来查找匹配where子句的行,但MYSQL不用index来解决order by:

          1:order by子句中使用不同indexes

    SELECT * FROM t1 ORDER BY key1, key2;

          2:使用不连续的index部分(联合key的非最左前缀)

    SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2;

          3:混合使用asc 和desc:

    SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;

          4:获得数据行的index(where子句中)和Order by 中使用的不一样

    SELECT * FROM t1 WHERE key2=constant ORDER BY key1;

          5:order by子句中使用index的表达式

    SELECT * FROM t1 ORDER BY ABS(key);
    SELECT * FROM t1 ORDER BY -key;

          6:join操作时,order by子句的列不全是第一个非 const表;

          7: 不同的order by,group by表达式:

          8:只对order by子句列的前缀加index,这种情况下index不能解决sort. e.g : order by列包含一个char(20)类型,但是只对前10bytes加index;

          9:table index无序,the index of hash(memory表);

        一个index是否排序可用可能受列的别名影响,表t1列 a 为索引:

    可以利用index来排序:

    SELECT a FROM t1 ORDER BY a;

    不能:

    SELECT ABS(a) AS a FROM t1 ORDER BY a;

            该语句中,order by引用的是列a, select子句的列名也是a, 但是他是别名,引用的是abs(a);

            下面的语句中,order by引用列名和select list中的列名不一样,但是select用到a,index sort可以使用(该语句的排序结果和以abs(a)排序的完全不一样)

    SELECT ABS(a) AS b FROM t1 ORDER BY a;

            默认的,mysql对所有的组col1,col2(group by col1,col2)排序,如果一个查询包含group by但是想避免sort的负载,可以压制排序通过order by null.

    INSERT INTO foo
    SELECT a, COUNT(*) FROM bar GROUP BY a ORDER BY NULL;

           依赖隐式的group by 排序在mysql5.6中被舍弃。更可取的是使用准确的order by子句。


           MYSQL有两种filesort算法来获得结果。原始的方法只使用order by中的列list. 改写过的方法不仅仅使用order by子句中的列,而是查询中所使用到的列。

           优化器选择哪个filesort算法?正常情况下使用第二种(BLOB TEXT等大对象列外),两种算法,都使用到sort_buffer_size系统变量:

           原始的filesort算法工作:

           1:根据key值或者scan all the table(where条件)读取所有满足条件的行,跳过不满足where子句的行。

           2:对于每一行,存储(key value, row id)对在sort buffer中。

           3: 如果所有上述对能全部放在sort buffer中,临时文件不会被创建,否则,当sort buffer满时,内存中执行quicksort并且把结果写进临时文件中,保存一个指针执行这个 sorted block.

           4:重复执行上述的过程,直到所有的行都被读取。

           5:执行一个多路归并排序,把第一个文件的block转移到另外一个临时文件中。重复执行,直到第一个文件内容全部在第二个文件中。

           6:一直merge buffer直到剩下2个block

           7:最后一次merge,只写入rowid到结果表

           8.根据排序结果中的rowid顺序读取数据。(手册中还提到了一个优化方案,但是我不认为能起到优化作用)。

         

          该filesort中出现两次读取操作,第一次在where子句判断,另外一次是在拍完value pairs后。然而即使第一次访问是连续读取(e.g. scan all the table),但是第二次他们是随机访问(尽管key排过序了,但是行位置没有~!);

           

          第二种filesort算法:(避开二次读,不是记录rowID,而是记录查询所使用的引用列)

         1:读取满足where子句的所有行

         2:对于每一行,元组记录key value和查询所引用到的列

         3:当buffer满时,排序并写入临时文件

         4:merge sort所有的临时文件,检索有序的行数据,直接从排过序的元组中读取需要的列而不是两次访问基表

       

         

          修改后的方法,列长于原来的方法。很有可能会产生大量IO,让排序变得很慢。为了避免这个问题,优化器会所有读取列的长度小于max_length_for_sort_data系统变量,才会选择修改后的算法。

          当filesort完成,explain输出中extra会有using filesort,优化器跟踪输出中filesort_summary块:

    "filesort_summary": {
      "rows": 100,
      "examined_rows": 100,
      "number_of_tmp_files": 0,
      "sort_buffer_size": 25192,
      "sort_mode": "<sort_key, additional_fields>"
    }

        其中sort mode就说了算法:

        <sort_key,rowid>表示原始的算法

        <sort_key,addtitional_filed>表示是修改后的算法

        为了提高排序速度,可以检查是否可以使用索引,如果不能使用:

           1.增加sort_buffer_size的大小

           2.增加read_rnd_buffer_size的大小

           3.通过表设计减少空间占用

           4.修改tmpdir目录指向专用文件系统

           如果order by没有使用索引,但是有limit子句,那么优化器可能可以避免合并临时文件,直接在内存中排序

  • 相关阅读:
    day9习题
    生产者消费者模型(吃包子例子)
    map 函数----filter函数
    #返回值包含函数
    #把函数当作参数传给另一个函数
    异常和错误!
    递归调用
    局部和全局案例!!
    全局变量与局部变量2
    全局变量与局部变量
  • 原文地址:https://www.cnblogs.com/onlysun/p/4535351.html
Copyright © 2011-2022 走看看