MySQL新旧版本ORDER BY 处理方法

MySQL 的order by 涉及到三个参数:
A. sort_buffer_size 排序缓存。
B. read_rnd_buffer_size 第二次排序缓存。
C. max_length_for_sort_data 带普通列的最大排序约束。

我来简单说下MySQL的排序规则。
假设查询语句select * from tb1 where 1 order by  a ; 字段a没有建立索引;以上三个参数都足够大。
MySQL内部有两种排序规则:
第一种,是普通的排序。
这种排序的特点是节省内存,但是最终会对磁盘有一次随机扫描。 大概主要过程如下:
1. 由于没有WHERE条件,所以直接对磁盘进行全表扫描,把字段a以及每行的物理ID(假设为TID)拿出来。然后把所有拿到的记录全部放到sort_buffer_size中进行排序。
2. 根据排好序的TID,从磁盘随机扫描所需要的所有记录,排好序后再次把所有必须的记录放到read_rnd_buffer_size中。
第二种,是冗余排序。这种排序的特点是不需要二次对磁盘进行随机扫描,但是缺点很明显,太浪费内存空间。
跟第一种不同的是,在第一步里拿到的不仅仅是字段a以及TID,而是把所有请求的记录全部拿到后,放到sort_buffer_size中进行排序。这样可以直接从缓存中返回记录给客户端,不用再次从磁盘上获取一次。
从MySQL 5.7 后,对第二种排序进行了打包压缩处理,避免太浪费内存。比如对于varchar(255)来说,实际存储为varchar(3)。那么相比之前的方式节约了好多内存,避免缓存区域不够时,建立磁盘临时表。

以下为简单的演示
mysql> use t_girl;
Database changed

三个参数的具体值:

mysql> select truncate(@@sort_buffer_size/1024/1024,2)||‘MB‘ as ‘sort_buffer_size‘,truncate(@@read_rnd_buffer_size/1024/1024,2)||‘MB‘ as read_rnd_buffer_zie,@@max_length_for_sort_data as max_length_for_sort_data;
+------------------+---------------------+--------------------------+
| sort_buffer_size | read_rnd_buffer_zie | max_length_for_sort_data |
+------------------+---------------------+--------------------------+
| 2.00MB           | 2.00MB              |                     1024 |
+------------------+---------------------+--------------------------+
1 row in set (0.00 sec)

演示表的相关数据:

mysql> select table_name,table_rows,concat(truncate(data_length/1024/1024,2),‘MB‘) as ‘table_size‘ from information_schema.tables where table_name = ‘t1‘ and table_schema = ‘t_girl‘;
+------------+------------+------------+
| table_name | table_rows | table_size |
+------------+------------+------------+
| t1         |    2092640 | 74.60MB    |
+------------+------------+------------+
1 row in set (0.00 sec)

开启优化器跟踪:

mysql> SET OPTIMIZER_TRACE="enabled=on",END_MARKERS_IN_JSON=on;
Query OK, 0 rows affected (0.00 sec)

从数据字典里面拿到跟踪结果:

mysql> select * from information_schema.optimizer_trace\G
*************************** 1. row ***************************
                            QUERY: select * from t1 where id < 10 order by id
                            TRACE: {
  "steps": [
    {
      "join_preparation": {
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `t1`.`id` AS `id`,`t1`.`log_time` AS `log_time` from `t1` where (`t1`.`id` < 10) order by `t1`.`id`"
          }
        ] /* steps */
      } /* join_preparation */
    },
    {
      "join_optimization": {
        "select#": 1,
        "steps": [
          {
            "condition_processing": {
              "condition": "WHERE",
              "original_condition": "(`t1`.`id` < 10)",
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "(`t1`.`id` < 10)"
                },
                {
                  "transformation": "constant_propagation",
                  "resulting_condition": "(`t1`.`id` < 10)"
                },
                {
                  "transformation": "trivial_condition_removal",
                  "resulting_condition": "(`t1`.`id` < 10)"
                }
              ] /* steps */
            } /* condition_processing */
          },
          {
            "table_dependencies": [
              {
                "table": "`t1`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ] /* depends_on_map_bits */
              }
            ] /* table_dependencies */
          },
          {
            "ref_optimizer_key_uses": [
            ] /* ref_optimizer_key_uses */
          },
          {
            "rows_estimation": [
              {
                "table": "`t1`",
                "table_scan": {
                  "rows": 2092640,
                  "cost": 4775
                } /* table_scan */
              }
            ] /* rows_estimation */
          },
          {
            "considered_execution_plans": [
              {
                "plan_prefix": [
                ] /* plan_prefix */,
                "table": "`t1`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "access_type": "scan",
                      "rows": 2.09e6,
                      "cost": 423303,
                      "chosen": true,
                      "use_tmp_table": true
                    }
                  ] /* considered_access_paths */
                } /* best_access_path */,
                "cost_for_plan": 423303,
                "rows_for_plan": 2.09e6,
                "sort_cost": 2.09e6,
                "new_cost_for_plan": 2.52e6,
                "chosen": true
              }
            ] /* considered_execution_plans */
          },
          {
            "attaching_conditions_to_tables": {
              "original_condition": "(`t1`.`id` < 10)",
              "attached_conditions_computation": [
              ] /* attached_conditions_computation */,
              "attached_conditions_summary": [
                {
                  "table": "`t1`",
                  "attached": "(`t1`.`id` < 10)"
                }
              ] /* attached_conditions_summary */
            } /* attaching_conditions_to_tables */
          },
          {
            "clause_processing": {
              "clause": "ORDER BY",
              "original_clause": "`t1`.`id`",
              "items": [
                {
                  "item": "`t1`.`id`"
                }
              ] /* items */,
              "resulting_clause_is_simple": true,
              "resulting_clause": "`t1`.`id`"
            } /* clause_processing */
          },
          {
            "refine_plan": [
              {
                "table": "`t1`",
                "access_type": "table_scan"
              }
            ] /* refine_plan */
          }
        ] /* steps */
      } /* join_optimization */
    },
    {
      "join_execution": {
        "select#": 1,
        "steps": [
          {
            "filesort_information": [
              {
                "direction": "asc",
                "table": "`t1`",
                "field": "id"
              }
            ] /* filesort_information */,
            "filesort_priority_queue_optimization": {
              "usable": false,
              "cause": "not applicable (no LIMIT)"
            } /* filesort_priority_queue_optimization */,
            "filesort_execution": [
            ] /* filesort_execution */,
            "filesort_summary": {
              "rows": 62390,
              "examined_rows": 2097152,
              "number_of_tmp_files": 0,
              "sort_buffer_size": 2097152,
              "sort_mode": "<sort_key, additional_fields>"
            } /* filesort_summary */
          }
        ] /* steps */
      } /* join_execution */
    }
  ] /* steps */
}
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0
          INSUFFICIENT_PRIVILEGES: 0
1 row in set (0.00 sec)

mysql>

其中以上红色部分<sort_key, additional_fields> 表示用了第二种排序规则。

其他的两种<sort_key, rowid> 以及<sort_key, packed_additional_fields>分别代表第一种和后续版本MySQL的提升, 自己体验去吧。

MySQL新旧版本ORDER BY 处理方法,布布扣,bubuko.com

时间: 2024-10-09 19:29:17

MySQL新旧版本ORDER BY 处理方法的相关文章

Android技巧小结之新旧版本Notification

最近开发用到了通知功能,但有几个地方老是提示deprecated,然后就找了篇文章学习了下新旧版本的不同. Notification即通知,用于在通知栏显示提示信息. 在较新的版本中(API level  > 11),Notification类中的一些方法被Android声明deprecated(弃用),其实基本上相当于全部弃用了,因为这个类本身方法就少得可怜. Android官方声明弃用,一定有它的理由,虽然我也不知道是什么.奈何本人轻度强迫症患者,人家都建议你不要用了,那就不要老是恪守着N年

浅谈 angular新旧版本问题

一直在学习angularJs,之前用的版本比较老,前些天更新了一下angularJs的版本,然后发现了一些问题,希望和大家分享一下. 在老的版本里控制器直接用函数定义就可以 比如: 在angularJs1.3.0中controller 直接写成函数就可以  但是在新版本里写控制器需要这样: 新版本里 我用的 1.3.9版本,必须定义angular.module,直接写成函数的形式angularJs不识别了. 然后今天我用angular-1.3.9写了一个route,一直在报错.我就想是不是版本的

第二章-第二题(每人自己建立一个HelloWorld项目,练习使用git的add/commit/push/pull/fetch/clone等基本命令。比较项目的新旧版本的差别。)--by侯伟婷

第二题:每人自己建立一个HelloWorld项目,练习使用git的add/commit/push/pull/fetch/clone等基本命令.比较项目的新旧版本的差别. 下面我将自己的练习结果和个人感受记录如下: 第一步:安装Git,设置自己的账号和邮箱,参见Git教程-廖雪峰的官方网站,网址如下参考资料1所示. 第二步:在Git中新建repository,名叫HelloWorld,并进行初始化,如图所示. 第三步:在HelloWorld版本库中新建了helloWorld.txt文件,用以练习G

linux V4L2驱动中新旧版本下video buffer alloc与mmap的处理区别

首先需要说明目前在比较新的内核中已经采用了 vb2_queue与vb2_buffer来替代旧版本内核中经常使用到的 videobuf_queue与videobuf_buffer. 两者主要用于对用户层申请VIDIOC_REQBUF时的使用. 从用户层Request的Memory的类型区分,典型的两种是: V4L2_MEMORY_USERPTR以及V4L2_MEMORY_MMAP,前者的内存主动权位于用户层,即驱动中的视频输出内存地址由用户层来提供,后者MMAP操作的内存缓存类型一般需要由驱动自己

移动端测试:优化原有功能,改动接口需要兼容新旧版本

在测试线下培训V1.0.1(月亮天使V4.8.0)时,因为在这个版本中改动了课程状态变更的逻辑,由原来的由教师点击上下课来更新课程状态,到根据排课时间,使用定时器来更新课程状态,在逻辑上有了很大的变化. 而且界面上,我的授课由原来的三个页签减少为两个,以及对应的角标数量统计等等多种情况.最初没有考虑到兼容旧版本的功能,导致修改后的接口对应不上,导致旧版的部分功能调用修改后的接口,返回参数异常等错误. 本次更新也不是强制更新的,所以后面修改接口或新增接口,兼容旧版本,以保证旧版本的正常运作,但是我

各新旧版本Java及其相关文档可以从这里下载

http://www.oracle.com/technetwork/java/archive-139210.html 各新旧版本Java及其相关文档可以从这里下载

[转帖]InfluxDB 1.2.0安装及新旧版本的注意事项

InfluxDB 1.2.0安装及新旧版本的注意事项 http://haibing.org/245?zwlqby=npztq3 挺好的文章 很好的解决了 上一个文档里面 关于 web admin 的问题 更多好文章见作者电子书集<Linux运维入门指南:生产运维需要掌握的技能> 随着大数据的爆发,系统数量也是直线上升,监控系统,收集系统运行状态成了保障业务正常运行中的重要一个环节. 针对这种产生频率快.带时间标签.测点多.信息量大的数据,时序数据库(Time Series Database,简

一个diff工具,用于判断两个目录下所有的改动(比较新旧版本文件夹)

需求: 编写一个diff工具,用于判断两个目录下所有的改动 详细介绍: 有A和B两个目录,目录所在位置及层级均不确定 需要以B为基准找出两个目录中所有有改动的文件(文件或内容增加.修改.删除),将有改动的文件放入第三个目录中,层级结构与原目录相同 将所有新增与更新信息记录到更新日志文件中 将删除信息单独记录到删除日志文件中 每次执行diff工具需要生成一个新的以日期命名的目录存放文件 使用场景: 本工具用于软件版本升级时找出两个版本间所有修改过的文件,便于增量替换. 提示:    使用CRC判断

Azure 国际篇_新旧版本迁移(二)_迁移VHD文件

如果要使用新版本ARM上的资源,例如虚拟网络,存储,网关等等,我们就要把旧版本的Classic 迁移到ARM上.迁移的办法非常简单. 现在RAM的"虚拟机(经典)"上找到旧版本的虚拟机DC01,接下来我们要把这台VM迁移到"虚拟机"这里. 新版本RAM上发虚拟机为空. 在RAM上新建资源组markleong 下载安装Azure Explore:http://storageexplorer.com/,安装完毕后,输入帐号登录,找到旧版本的虚拟机VHD文件.关闭虚拟机后