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的提升, 自己體驗去吧。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章