zoukankan      html  css  js  c++  java
  • mysql order by是怎么工作的

    查询语句:select city,name,age from table where city='杭州' order by name limit 1000;
    上面这条sql语句的执行流程,怎么执行,以及什么参数会影响执行的行为
     
    首先给city字段加索引之后,使用explain命令查看语句执行情况,会发现有using filesort,这就是表示要排序。
    mysql会给每个线程分配一块内存用于排序,称为sort_buffer
     
    以上这条语句的执行流程:
    1、初始化sort_buffer,确定放入了name age city三个字段
    2、从索引city找到第一个满足city=杭州的条件的主键id,
    3、到主键id索引取出整行,取name、city、age三个字段的值,存入sort_buffer中
    4、从索引city取下一个记录的主键id
    5、重复3、4直到city不满足查询条件为止
    6、对sort_buffer中的数据按照字段name做快速排序
    7、按照排序结果取前1000行返回客户端
     
     
    sort_buffer_size就是mysql为排序开辟的内存(sort_buffer)的大小,如果要排序的数据量小于sort_buffer_size,排序就在内存中完成,如果排序数据量太多,内存放不下,则不得不利用磁盘临时文件辅助排序
     
    虽然在定义字段的时候使用varchar(18),但在排序过程中还是要按照实际长度来分配空间的
     
    上面的算法过程中,只对原标数据读了一遍,剩下的操作都是在sort_buffer和临时文件总执行的,这个算法有个问题就是,如果查询要返回很多字段的话,那么sort_buffer里面要放的字段数太多,这样内存里能够同时放下的行数很少,要分成很多个临时文件,排序的性能就差
    所以单行很多,这个方法效率就不好
     
    SET max_length_for_sort_data = 16;
    设置这个参数,如果单行的长度超过这个值,mysql就认为单行太大,要换一个算法
    设置这个参数,整个执行流程就变了样子
    1、初始化sort_buffer
    2、从索引city找到第一个满足city=杭州条件的主键id
    3、到主键id索引取出整行,取name、id这两个字段,存放sort_buffer中
    4、从索引city取下一个记录id
    5、重复3、4
    这种执行流程又称为rowid排序
     
     
    这两种排序得出的结论:
    1、mysql实在是担心排序内存太小,会影响排序效率,才会采用rowid排序算法,这样排序过程中一次可以排序更多行,但是需要再回到原表去取数据
     
    2、mysql认为内存足够大,会优先选择全字段排序,把需要的字段都放到sort_buffer中,这样排序后就会之间从内存里面返回查询结果了,不会再回到原表去取数据
     
    这就体现了mysql的一个设计思想:如果内存够,就要多利用内存,尽量减少磁盘访问
     
    对于innodb表来说,rowid排序会要求回表多造成磁盘读,因此不会被优先选择
     
    所以了解了以上两种算法,才发现排序对于mysql是一个成本比较高的操作,其实,并不是所有的order by语句都需要排序,从上面分享的执行结果,我们可以看到,mysql之所以需要生成临时表,并且临时表上做排序操作,其原因是原来的数据都是无序的
     
    所以,我们修改刚才的表索引
    alter table t add index city_user(city, name);
    创建联合索引
    再次使用explain查看语句就会发现没有using filesort
     
    这就是为什么在很多优化的文章中出现如果使用explain命令有using filesort就需要优化的原因了
     
    以上就是学习极客时间中mysql实战中的文章,具体可以去学习,我只是根据自己的理解做个笔记。
     

  • 相关阅读:
    通过反射获取Android通知栏高度
    Android 的EditText实现不可编辑
    Android 代码混淆、第三方平台加固加密、渠道分发 完整教程(图文)
    eclipse、myeclipse,svn插件subclipse 忘记密码的解决方法(win7、win8、xp)
    Eclipse 基于接口编程的时候,快速跳转到实现类的方法(图文)
    WIN7、WIN8 右键在目录当前打开命令行Cmd窗口(图文)
    eclipse,myeclipse开发环境下,maven远程部署到tomcat7服务器(图文)
    python之路——博客目录
    生成器和协程 —— 你想知道的都在这里了
    python3.7导入gevent模块报错的解决方案
  • 原文地址:https://www.cnblogs.com/weiluoyan/p/10397939.html
Copyright © 2011-2022 走看看