63 MySQL實戰性能優化-optimizer_trace分析sql與單路與雙路排序區別

1,mysql索引性能優化最佳實戰

2, 使用索引查詢如何避免回表查詢

3,爲什麼查詢有時候加了索引也會失效?

4,如何使用 optimizer_trace 分析sql語句

5,order by 排序優化原則有哪些?

6 mysql排序支持2種 filesort 和index 的區別

7,Mysqlfilesort 排序底層實現原理

8, 單路與雙路(回表)排序底層原理。

9, 爲什麼阿里巴巴手冊不推薦使用存儲過程?

Using index: 查詢的列都是加上索引,不需要回表查詢。
什麼是回表查詢:
select * from table where name='bob'
底層先查詢username索引文件查找對應的username 'bob'的主鍵id
在根據主鍵id 查詢主鍵索引文件 對應行數據。

如果全表掃描查詢效率比索引 查詢要高,則使用全表掃描。


如果用name索引查找數據需要遍歷name字段聯合索引樹,然後根據遍歷出來的主鍵值去主鍵索引樹裏再去查找最終的數據,成本比全表掃描還高。
可以覆蓋索引優化,這樣系需要遍歷name字段的聯合索引樹就可以拿到所有的結果。


誤區:
1, 所有的字段加上了索引 就一定使用索引查詢
2,全表掃描查詢是否一定會比索引查詢慢。
排序的2種算法,
1, using filesort 索引失效 沒有根據索引字段排序的情況
2, using index 根據索引的字段排序

可以看到通過select出的字段是覆蓋索引,MySQL底層使用了索引優化。可以使用optimizer_trace 分析sql是否有走過索引:

optimizer_trace 分析sql 語句
如果全表查詢效率比索引要高,則使用全表掃描。


如果用name 索引查找數據需要遍歷name字段聯合索引樹,然後根據遍歷出來的主鍵值再去查找最終的數據,成本比全表掃描要高。
可以使用覆蓋索引,這樣只需要遍歷name的字段聯合索引樹就可以查找到結果:


SET  optimizer_trace='enabled=on',end_markers_in_json=on;


SELECT * FROM employees WHERE name > 'mayikt' ;
SELECT * FROM information_schema.OPTIMIZER_TRACE;


查詢結果:

{
  "steps": [
    {
      "join_preparation": { --第一階段:SQl準備階段
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `employees`.`id` AS `id`,`employees`.`name` AS `name`,`employees`.`age` AS `age`,`employees`.`position` AS `position`,`employees`.`hire_time` AS `hire_time` from `employees` where (`employees`.`name` > 'mayikt')"
          }
        ] /* steps */
      } /* join_preparation */
    },
    {
      "join_optimization": { --第二階段:SQL優化階段
        "select#": 1,
        "steps": [
          {
            "condition_processing": { --條件處理
              "condition": "WHERE",
              "original_condition": "(`employees`.`name` > 'mayikt')",
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "(`employees`.`name` > 'mayikt')"
                },
                {
                  "transformation": "constant_propagation",
                  "resulting_condition": "(`employees`.`name` > 'mayikt')"
                },
                {
                  "transformation": "trivial_condition_removal",
                  "resulting_condition": "(`employees`.`name` > 'mayikt')"
                }
              ] /* steps */
            } /* condition_processing */
          },
          {
            "substitute_generated_columns": {
            } /* substitute_generated_columns */
          },
          {
            "table_dependencies": [ --表依賴詳情
              {
                "table": "`employees`",
                "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": "`employees`",
                "range_analysis": { --全表掃描情況
                  "table_scan": {
                    "rows": 68511, --掃描行數
                    "cost": 13929 --查詢成本
                  } /* table_scan */,
                  "potential_range_indexes": [ --查詢可能使用的索引
                    {
                      "index": "PRIMARY", --主鍵索引
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_name_age_position", --輔助索引
                      "usable": true,
                      "key_parts": [
                        "name",
                        "age",
                        "position",
                        "id"
                      ] /* key_parts */
                    }
                  ] /* potential_range_indexes */,
                  "setup_range_conditions": [
                  ] /* setup_range_conditions */,
                  "group_index_range": {
                    "chosen": false,
                    "cause": "not_group_by_or_distinct"
                  } /* group_index_range */,
                  "analyzing_range_alternatives": { ‐‐分析各個索引使用成本
                    "range_scan_alternatives": [
                      {
                        "index": "idx_name_age_position",
                        "ranges": [
                          "mayikt < name"
                        ] /* ranges */,
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": false,
                        "using_mrr": false,
                        "index_only": false,
                        "rows": 34255, --‐‐索引掃描行數
                        "cost": 41107, --索引使用成本
                        "chosen": false, ‐‐是否選擇該索引
                        "cause": "cost"
                      }
                    ] /* range_scan_alternatives */,
                    "analyzing_roworder_intersect": {
                      "usable": false,
                      "cause": "too_few_roworder_scans"
                    } /* analyzing_roworder_intersect */
                  } /* analyzing_range_alternatives */
                } /* range_analysis */
              }
            ] /* rows_estimation */
          },
          {
            "considered_execution_plans": [
              {
                "plan_prefix": [
                ] /* plan_prefix */,
                "table": "`employees`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "rows_to_scan": 68511,
                      "access_type": "scan",
                      "resulting_rows": 68511,
                      "cost": 13927,
                      "chosen": true
                    }
                  ] /* considered_access_paths */
                } /* best_access_path */,
                "condition_filtering_pct": 100,
                "rows_for_plan": 68511,
                "cost_for_plan": 13927,
                "chosen": true
              }
            ] /* considered_execution_plans */
          },
          {
            "attaching_conditions_to_tables": {
              "original_condition": "(`employees`.`name` > 'mayikt')",
              "attached_conditions_computation": [
              ] /* attached_conditions_computation */,
              "attached_conditions_summary": [
                {
                  "table": "`employees`",
                  "attached": "(`employees`.`name` > 'mayikt')"
                }
              ] /* attached_conditions_summary */
            } /* attaching_conditions_to_tables */
          },
          {
            "refine_plan": [
              {
                "table": "`employees`"
              }
            ] /* refine_plan */
          }
        ] /* steps */
      } /* join_optimization */
    },
    {
      "join_execution": { --第三階段:SQL執行階段
        "select#": 1,
        "steps": [
        ] /* steps */
      } /* join_execution */
    }
  ] /* steps */
}
全表掃描的成本低於索引掃描, 索引MySQL最終會選擇全表掃描。


Order by 培訓優化原則

1,.EXPLAIN SELECT * FROM employees WHERE name= 'meite' AND  position ='ceo' order by age;

分析: 利用最左前綴法則: 中間字段不能斷,因此查詢到了name 索引
,從key_len=74 也能看出,age索引列用在排序過程中,因爲Extra 字段裏沒有
using filesort 是爲Using index condition

2,EXPLAIN SELECT * FROM employees WHERE name= 'meite' order by position;

從explain 的執行結果來看: key_len=74, 查詢使用了name 索引,由於
用了position 進行排序,跳過了age,出現了Using filesort

3.EXPLAIN SELECT * FROM employees WHERE name= 'meite' order by age,position;

分析:
查找只用到索引 name, age 和position 用於排序。,無Using filesort.

4.EXPLAIN SELECT * FROM employees WHERE name= 'meite' order by position,age;

分析:
在 Extra中出現 Using Filesort, 因爲age 爲常量,在排序中被優化,所以索引未顛倒,會出現Using Filesort

5.
EXPLAIN SELECT * FROM employees WHERE name= 'meite' order by age asc ,position desc ;

分析: age字段採用升序排序,position 降序排序 導致索引的排序方式不同,從而產生 Using filesort

EXPLAIN SELECT * FROM employees WHERE name in('meite','xiaowei') order by age, position;

f

分析: 對於多個排序來說,多個相等條件也是範圍查詢。
7, EXPLAIN SELECT * FROM employees WHERE name>'meite' order by name;

可以優化爲

EXPLAIN SELECT name,age,position FROM employees WHERE name>'meite' order by name;

排序優化總結


Mysql排序支持兩種filesort和index
1.這種方式在使用explain分析時顯示爲using index,不需要額外的排序, 是指mysql掃描索引本身完成排序,操作效率較高
2.通過對返回數據進行排序,即filesort,所有不通過索引直接返回排序結果的排序都是filesort排序
Filesort實現原理:
filesort通過相應的排序算法,將取得的數據在sort_buffer_size系統變量設置的內存排序區中進行排序,如果內存裝載不下,會將磁盤上的數據進行分塊,再對各個數據塊進行排序,再將各個塊合併成有序的結果集。

order by滿足兩種情況會使用Using index。

  1. order by語句使用索引最左前列。
  2. 使用where子句與order by子句條件列組合滿足索引最左前列。
    3、儘量在索引列上完成排序,遵循索引建立(索引創建的順序)時的最左前綴法則。
    4、如果order by的條件不在索引列上,就會產生Using filesort。
    5、能用覆蓋索引儘量用覆蓋索引
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章