视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
【原创】MySQL新旧版本ORDERBY处理方法
2020-11-09 16:23:17 责编:小采
文档


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 ;

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 | 20920 | 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": 20920,
 "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": ""
 } /* filesort_summary */
 }
 ] /* steps */
 } /* join_execution */
 }
 ] /* steps */
}
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0
 INSUFFICIENT_PRIVILEGES: 0
1 row in set (0.00 sec)
mysql>


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

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

下载本文
显示全文
专题