您的位置:首页 > 数据库 > MySQL

MYSQL排序ORDER BY

2021-03-06 20:55 891 查看

MYSQL排序ORDER BY

祖仙教小凡仙 海鲨数据库架构师

在我编写的数据库规范当中有禁止排序这一条的,虽然它是基于ORACLE的规范。不过这条基本是所有数据库的通用规范!
JAVA开发ORACLE的规范
为什么要禁止呢?因为排序需要数据库内存,需要消耗CPU时间,需要用到数据库的磁盘操作。就重要的是数据库端无法分布式,也就是说不仅仅是你一个程序的SQL要排序,其它SQL也要排序。这些SQL会因为并发用户的操作给数据库下达无数多的SQL排序工作任务。而数据库无法把这些工作分担给别的数据库服务器。不像应用服务器TOMCAT,通过NGINX无状态的负载均衡到不同的物理服务机上部署相同的TOMCAT服务器上。而数据库就一个主库,顶多通过多个备库来稍微分担点只读查询,而且对于数据及时性不高的SQL。
而这分担也需要开发人员在程序上进行调整。还不如直接在JAVA程序里完成排序操作来的简单方便明了可靠。
我们看下MYSQL的排序操作:

CITY有个二级索引,辅助索引。主键是ID。
这个语句的流程如下:

第一 我们根据索引CITY找到ID,
第二 然后根据ID回表找到行,再取出CITY,NAME,AGE 3个字段。
第三 把这3个字段放入排序内存,进行排序;
第四 把排序结果集 前1000条发给客户;
排序内存大小参数是:SORT_BUFFER_SIZE 。它是每线程的。

排序内存大小是每个字段的定义大小累加再乘以行数。
比如说NAME 定义VARCAHR(16) 存了中国人名字。根据中文占3个位置来算,很多行实际上有很多用不到那么多。可排序就定义来申请内存大小。

另外个参数 MAX_LENGTH_FOR_SORT_DATA 大意是说如果参与排序的字段累加大小超过该参数的值,那MYSQL就换一种排序算法。MYSQL就取出排序字段,又多少个排序字段就取出多少个,外加ID。
ORDER BY NAME .....

第1 根据索引CITY找到ID
第2 根据ID找到行,取出NAME+ID
第3 把NAME+ID放入排序内存,进行排序
第4 从排序好的内存里取出ID,回表取出相关的字段SELECT部分,发给客户。

下面操作是检查某个SQL排序操作情况

/* 打开optimizer_trace,只对本线程有效 */
SET optimizer_trace='enabled=on';

/* @a保存Innodb_rows_read的初始值 */
select VARIABLE_VALUE into @a from  performance_schema.session_status where variable_name = 'Innodb_rows_read';

/* 执行语句 */
select city, name,age from t where city='赣州' order by name limit 1000;

/* 查看 OPTIMIZER_TRACE 输出 */
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`\G

/* @b保存Innodb_rows_read的当前值 */
select VARIABLE_VALUE into @b from performance_schema.session_status where variable_name = 'Innodb_rows_read';

/* 计算Innodb_rows_read差值 */
select @b-@a;
会显示如下结果:


排序行数,使用到临时文件个数,排序内存大小,排序算法。
OPTIMIZER_TRACE:SORT_MODE=<SOTR_KEY,ROWID>
而原来全字段排序模式:
SORT_MODE=<SOTR_KEY,PACKED_ADDITIONAL_FILEDS>

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: