mysql 執行計划分析三看, explain,profiling,optimizer_trace


http://blog.csdn.net/xj626852095/article/details/52767963

step 1

 使用explain 查看執行計划, 5.6后可以加參數 explain format=json xxx 輸出json格式的信息

 

step 2 

使用profiling詳細的列出在每一個步驟消耗的時間,前提是先執行一遍語句

 

#打開profiling 的設置
SET profiling = 1;
SHOW VARIABLES LIKE '%profiling%';

#查看隊列的內容
show profiles;  
#來查看統計信息
show profile block io,cpu for query 3;


step 3  

 

Optimizer trace是MySQL5.6添加的新功能,可以看到大量的內部查詢計划產生的信息, 先打開設置,然后執行一次sql,最后查看`information_schema`.`OPTIMIZER_TRACE`的內容

 

#打開設置
SET optimizer_trace='enabled=on';  
#最大內存根據實際情況而定, 可以不設置
SET OPTIMIZER_TRACE_MAX_MEM_SIZE=1000000;
SET END_MARKERS_IN_JSON=ON;
SET optimizer_trace_limit = 1;
SHOW VARIABLES LIKE '%optimizer_trace%';

#執行所需sql后,查看該表信息即可看到詳細的執行過程
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`;

 

 

 

MySQL索引選擇不正確並詳細解析OPTIMIZER_TRACE格式

http://blog.csdn.net/melody_mr/article/details/48950601

一 表結構如下: 

CREATE TABLE t_audit_operate_log (
  Fid bigint(16) AUTO_INCREMENT,
  Fcreate_time int(10) unsigned NOT NULL DEFAULT '0',
  Fuser varchar(50) DEFAULT '',
  Fip bigint(16) DEFAULT NULL,
  Foperate_object_id bigint(20) DEFAULT '0',
  PRIMARY KEY (Fid),
  KEY indx_ctime (Fcreate_time),
  KEY indx_user (Fuser),
  KEY indx_objid (Foperate_object_id),
  KEY indx_ip (Fip)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

執行查詢:

MySQL> explain select count(*) from t_audit_operate_log where Fuser='XX@XX.com' and Fcreate_time>=1407081600 and Fcreate_time<=1407427199\G

*************************** 1. row ***************************

id: 1

select_type: SIMPLE

table: t_audit_operate_log

type: ref

possible_keys: indx_ctime,indx_user

key: indx_user

key_len: 153

ref: const

rows: 2007326

Extra: Using where

 

發現,使用了一個不合適的索引, 不是很理想,於是改成指定索引:

mysql> explain select count(*) from t_audit_operate_log use index(indx_ctime) where Fuser='CY6016@cyou-inc.com' and Fcreate_time>=1407081600 and Fcreate_time<=1407427199\G

*************************** 1. row ***************************

id: 1

select_type: SIMPLE

table: t_audit_operate_log

type: range

possible_keys: indx_ctime

key: indx_ctime

key_len: 5

ref: NULL

rows: 670092

Extra: Using where

實際執行耗時,后者比前者快了接近10

問題: 很奇怪,優化器為何不選擇使用 indx_ctime 索引,而選擇了明顯會掃描更多行的 indx_user 索引。

分析2個索引的數據量如下:  兩個條件的唯一性對比:

select count(*) from t_audit_operate_log where Fuser='XX@XX.com';
+----------+
| count(*) |
+----------+
| 1238382 | 
+----------+

select count(*) from t_audit_operate_log where Fcreate_time>=1407254400 and Fcreate_time<=1407427199;
+----------+
| count(*) |
+----------+
| 198920 | 
+----------+

顯然,使用索引indx_ctime好於indx_user,但MySQL卻選擇了indx_user. 為什么?

於是,使用 OPTIMIZER_TRACE進一步探索.

 

二  OPTIMIZER_TRACE的過程說明

以本處事例簡要說明OPTIMIZER_TRACE的過程.

查看OPTIMIZER_TRACE方法:

1.set optimizer_trace='enabled=on';    --- 開啟trace

2.set optimizer_trace_max_mem_size=1000000;    --- 設置trace大小

3.set end_markers_in_json=on;    --- 增加trace中注釋

4.select * from information_schema.optimizer_trace\G;

 

[plain]  view plain  copy 
 
  1. {\  
  2.   "steps": [\  
  3.     {\  
  4.       "join_preparation": {\  ---優化准備工作  
  5.         "select#": 1,\  
  6.         "steps": [\  
  7.           {\  
  8.             "expanded_query": "/* select#1 */ select count(0) AS `count(*)` from `t_audit_operate_log` where ((`t_audit_operate_log`.`Fuser` = 'XX@XX.com') and (`t_audit_operate_log`.`Fcreate_time` >= 1407081600) and (`t_audit_operate_log`.`Fcreate_time` <= 1407427199))"\  
  9.           }\  
  10.         ] /* steps */\  
  11.       } /* join_preparation */\  
  12.     },\  
  13.     {\  
  14.       "join_optimization": {\  ---優化工作的主要階段,包括邏輯優化和物理優化兩個階段  
  15.         "select#": 1,\  
  16.         "steps": [\  ---優化工作的主要階段, 邏輯優化階段  
  17.           {\  
  18.             "condition_processing": {\  ---邏輯優化,條件化簡  
  19.               "condition": "WHERE",\  
  20.               "original_condition": "((`t_audit_operate_log`.`Fuser` = 'XX@XX.com') and (`t_audit_operate_log`.`Fcreate_time` >= 1407081600) and (`t_audit_operate_log`.`Fcreate_time` <= 1407427199))",\  
  21.               "steps": [\  
  22.                 {\  
  23.                   "transformation": "equality_propagation",\  ---邏輯優化,條件化簡,等式處理  
  24.                   "resulting_condition": "((`t_audit_operate_log`.`Fuser` = 'XX@XX.com') and (`t_audit_operate_log`.`Fcreate_time` >= 1407081600) and (`t_audit_operate_log`.`Fcreate_time` <= 1407427199))"\  
  25.                 },\  
  26.                 {\  
  27.                   "transformation": "constant_propagation",\  ---邏輯優化,條件化簡,常量處理  
  28.                   "resulting_condition": "((`t_audit_operate_log`.`Fuser` = 'XX@XX.com') and (`t_audit_operate_log`.`Fcreate_time` >= 1407081600) and (`t_audit_operate_log`.`Fcreate_time` <= 1407427199))"\  
  29.                 },\  
  30.                 {\  
  31.                   "transformation": "trivial_condition_removal",\  ---邏輯優化,條件化簡,條件去除  
  32.                   "resulting_condition": "((`t_audit_operate_log`.`Fuser` = 'XX@XX.com') and (`t_audit_operate_log`.`Fcreate_time` >= 1407081600) and (`t_audit_operate_log`.`Fcreate_time` <= 1407427199))"\  
  33.                 }\  
  34.               ] /* steps */\  
  35.             } /* condition_processing */\  
  36.           },\  ---邏輯優化,條件化簡,結束  
  37.           {\  
  38.             "table_dependencies": [\  ---邏輯優化, 找出表之間的相互依賴關系. 非直接可用的優化方式.   
  39.               {\  
  40.                 "table": "`t_audit_operate_log`",\  
  41.                 "row_may_be_null": false,\  
  42.                 "map_bit": 0,\  
  43.                 "depends_on_map_bits": [\  
  44.                 ] /* depends_on_map_bits */\  
  45.               }\  
  46.             ] /* table_dependencies */\  
  47.           },\  
  48.           {\  
  49.             "ref_optimizer_key_uses": [\   ---邏輯優化,  找出備選的索引  
  50.               {\  
  51.                 "table": "`t_audit_operate_log`",\  
  52.                 "field": "Fuser",\  
  53.                 "equals": "'XX@XX.com'",\  
  54.                 "null_rejecting": false\  
  55.               }\  
  56.             ] /* ref_optimizer_key_uses */\  
  57.           },\  
  58.           {\  
  59.             "rows_estimation": [\   ---邏輯優化, 估算每個表的元組個數. 單表上進行全表掃描和索引掃描的代價估算. 每個索引都估算索引掃描代價  
  60.               {\  
  61.                 "table": "`t_audit_operate_log`",\  
  62.                 "range_analysis": {\  
  63.                   "table_scan": {\---邏輯優化, 估算每個表的元組個數. 單表上進行全表掃描的代價  
  64.                     "rows": 8150516,\  
  65.                     "cost": 1.73e6\  
  66.                   } /* table_scan */,\  
  67.                   "potential_range_indices": [\ ---邏輯優化, 列出備選的索引. 后續版本字符串變為potential_range_indexes  
  68.                     {\  
  69.                       "index": "PRIMARY",\---邏輯優化, 本行表明主鍵索引不可用  
  70.                       "usable": false,\  
  71.                       "cause": "not_applicable"\  
  72.                     },\  
  73.                     {\  
  74.                       "index": "indx_ctime",\---邏輯優化, 索引indx_ctime  
  75.                       "usable": true,\  
  76.                       "key_parts": [\  
  77.                         "Fcreate_time",\  
  78.                         "Fid"\  
  79.                       ] /* key_parts */\  
  80.                     },\  
  81.                     {\  
  82.                       "index": "indx_user",\---邏輯優化, 索引indx_user  
  83.                       "usable": true,\  
  84.                       "key_parts": [\  
  85.                         "Fuser",\  
  86.                         "Fid"\  
  87.                       ] /* key_parts */\  
  88.                     },\  
  89.                     {\  
  90.                       "index": "indx_objid",\---邏輯優化, 索引  
  91.                       "usable": false,\  
  92.                       "cause": "not_applicable"\  
  93.                     },\  
  94.                     {\  
  95.                       "index": "indx_ip",\---邏輯優化, 索引  
  96.                       "usable": false,\  
  97.                       "cause": "not_applicable"\  
  98.                     }\  
  99.                   ] /* potential_range_indices */,\  
  100.                   "setup_range_conditions": [\ ---邏輯優化, 如果有可下推的條件,則帶條件考慮范圍查詢  
  101.                   ] /* setup_range_conditions */,\  
  102.                   "group_index_range": {\---邏輯優化, 如帶有GROUPBY或DISTINCT,則考慮是否有索引可優化這種操作. 並考慮帶有MIN/MAX的情況  
  103.                     "chosen": false,\  
  104.                     "cause": "not_group_by_or_distinct"\  
  105.                   } /* group_index_range */,\  
  106.                   "analyzing_range_alternatives": {\---邏輯優化,開始計算每個索引做范圍掃描的花費(等值比較是范圍掃描的特例)  
  107.                     "range_scan_alternatives": [\  
  108.                       {\  
  109.                         "index": "indx_ctime",\ ---[A]  
  110.                         "ranges": [\  
  111.                           "1407081600 <= Fcreate_time <= 1407427199"\  
  112.                         ] /* ranges */,\  
  113.                         "index_dives_for_eq_ranges": true,\  
  114.                         "rowid_ordered": false,\  
  115.                         "using_mrr": true,\  
  116.                         "index_only": false,\  
  117.                         "rows": 688362,\  
  118.                         "cost": 564553,\ ---邏輯優化,這個索引的代價最小  
  119.                         "chosen": true\ ---邏輯優化,這個索引的代價最小,被選中. (比前面的table_scan 和其他索引的代價都小)  
  120.                       },\  
  121.                       {\  
  122.                         "index": "indx_user",\  
  123.                         "ranges": [\  
  124.                           "XX@XX.com <= Fuser <= XX@XX.com"\  
  125.                         ] /* ranges */,\  
  126.                         "index_dives_for_eq_ranges": true,\  
  127.                         "rowid_ordered": true,\  
  128.                         "using_mrr": true,\  
  129.                         "index_only": false,\  
  130.                         "rows": 1945894,\  
  131.                         "cost": 1.18e6,\  
  132.                         "chosen": false,\  
  133.                         "cause": "cost"\  
  134.                       }\  
  135.                     ] /* range_scan_alternatives */,\  
  136.                     "analyzing_roworder_intersect": {\  
  137.                       "usable": false,\  
  138.                       "cause": "too_few_roworder_scans"\  
  139.                     } /* analyzing_roworder_intersect */\  
  140.                   } /* analyzing_range_alternatives */,\---邏輯優化,開始計算每個索引做范圍掃描的花費. 這項工作結算  
  141.                   "chosen_range_access_summary": {\---邏輯優化,開始計算每個索引做范圍掃描的花費. 總結本階段最優的.  
  142.                     "range_access_plan": {\  
  143.                       "type": "range_scan",\  
  144.                       "index": "indx_ctime",\  
  145.                       "rows": 688362,\  
  146.                       "ranges": [\  
  147.                         "1407081600 <= Fcreate_time <= 1407427199"\  
  148.                       ] /* ranges */\  
  149.                     } /* range_access_plan */,\  
  150.                     "rows_for_plan": 688362,\  
  151.                     "cost_for_plan": 564553,\  
  152.                     "chosen": true\    -- 這里看到的cost和rows都比 indx_user 要來的小很多---這個和[A]處是一樣的,是信息匯總.  
  153.                   } /* chosen_range_access_summary */\  
  154.                 } /* range_analysis */\  
  155.               }\  
  156.             ] /* rows_estimation */\ ---邏輯優化, 估算每個表的元組個數. 行估算結束  
  157.           },\  
  158.           {\  
  159.             "considered_execution_plans": [\ ---物理優化, 開始多表連接的物理優化計算  
  160.               {\  
  161.                 "plan_prefix": [\  
  162.                 ] /* plan_prefix */,\  
  163.                 "table": "`t_audit_operate_log`",\  
  164.                 "best_access_path": {\  
  165.                   "considered_access_paths": [\  
  166.                     {\  
  167.                       "access_type": "ref",\ ---物理優化, 計算indx_user索引上使用ref方查找的花費,  
  168.                       "index": "indx_user",\  
  169.                       "rows": 1.95e6,\  
  170.                       "cost": 683515,\  
  171.                       "chosen": true\  
  172.                     },\ ---物理優化, 本應該比較所有的可用索引,即打印出多個格式相同的但索引名不同的內容,這里卻沒有。推測是bug--沒有遍歷每一個索引.  
  173.                     {\  
  174.                       "access_type": "range",\---物理優化,猜測對應的是indx_time(沒有實例可進行調試,對比5.7的跟蹤信息猜測而得)  
  175.                       "rows": 516272,\  
  176.                       "cost": 702225,\---物理優化,代價大於了ref方式的683515,所以沒有被選擇  
  177.                       "chosen": false\   -- cost比上面看到的增加了很多,但rows沒什么變化 ---物理優化,此索引沒有被選擇  
  178.                     }\  
  179.                   ] /* considered_access_paths */\  
  180.                 } /* best_access_path */,\  
  181.                 "cost_for_plan": 683515,\ ---物理優化,匯總在best_access_path 階段得到的結果  
  182.                 "rows_for_plan": 1.95e6,\  
  183.                 "chosen": true\   -- cost比上面看到的竟然小了很多?雖然rows沒啥變化  ---物理優化,匯總在best_access_path 階段得到的結果  
  184.               }\  
  185.             ] /* considered_execution_plans */\  
  186.           },\  
  187.           {\  
  188.             "attaching_conditions_to_tables": {\---邏輯優化,盡量把條件綁定到對應的表上  
  189.               } /* attaching_conditions_to_tables */\  
  190.           },\  
  191.           {\  
  192.             "refine_plan": [\  
  193.               {\  
  194.                 "table": "`t_audit_operate_log`",\---邏輯優化,下推索引條件"pushed_index_condition";其他條件附加到表上做為過濾條件"table_condition_attached"  
  195.               }\  
  196.             ] /* refine_plan */\  
  197.           }\  
  198.         ] /* steps */\  
  199.       } /* join_optimization */\ \---邏輯優化和物理優化結束  
  200.     },\  
  201.     {\  
  202.       "join_explain": {} /* join_explain */\  
  203.     }\  
  204.   ] /* steps */\  

 

 

三 其他一個相似問題
單表掃描,使用ref和range從索引獲取數據一例  
http://blog.163.com/li_hx/blog/static/183991413201461853637715/

 


四 問題的解決方式

遇到單表上有多個索引的時候,在MySQL5.6.20版本之前的版本,需要人工強制使用索引,以達到最好的效果.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM