跟踪MYSQL 的查询优化过程方法
http://dev.mysql.com/doc/internals/en/tracing-example.html
http://blog.chinaunix.net/uid-20785090-id-5597524.html
handle_select() mysql_select() JOIN::prepare() setup_fields() JOIN::optimize() /* optimizer is from here ... */ optimize_cond() opt_sum_query() make_join_statistics() get_quick_record_count() choose_plan() /* Find the best way to access tables */ /* as specified by the user. */ optimize_straight_join() best_access_path() /* Find a (sub-)optimal plan among all or subset */ /* of all possible query plans where the user */ /* controls the exhaustiveness of the search. */ greedy_search() best_extension_by_limited_search() best_access_path() /* Perform an exhaustive search for an optimal plan */ find_best() make_join_select() /* ... to here */ JOIN::exec()
CREATE TABLE `t` ( `a` int(11) NOT NULL, `b` int(11) DEFAULT NULL, `c` int(11) NOT NULL, PRIMARY KEY (`a`), KEY `b` (`b`), KEY `ix` (`b`,`c`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
json格式:
mysql> explain format=json select b from t\G *************************** 1. row ********************** EXPLAIN: { "query_block": { "select_id": 1, "cost_info": { "query_cost": "1.20" }, "table": { "table_name": "t", "access_type": "index", "key": "b", "used_key_parts": [ "b" ], "key_length": "5", "rows_examined_per_scan": 1, "rows_produced_per_join": 1, "filtered": "100.00", "using_index": true, "cost_info": { "read_cost": "1.00", "eval_cost": "0.20", "prefix_cost": "1.20", "data_read_per_join": "16" }, "used_columns": [ "b" ] } } } 1 row in set, 1 warning (0.00 sec)
更加详细的过程生成:
1.set optimizer_trace_max_mem_size=300000;
2.set end_markers_in_json=true;
3.set optimizer_trace="enabled=on";
4.sql语句
5.select trace from information_schema.optimizer_trace\G;
6.set optimizer_trace="enabled=off";
主要分为三个部分
join_preparation:SQL的准备阶段,sql被格式化
对应函数 JOIN::prepare
join_optimization:SQL优化阶段
对应函数JOIN::optimize
join_execution:SQL执行阶段
对应函数:JOIN::exec
join_optimization是核心。
下面详细介绍join_optimization的过程:
1)condition_processing阶段,进行where条件处理,分别是相等处理,常量处理,删除冗余条件
2)ref_optimizer_key_uses阶段,查找可进行ref type访问的索引(索引的等值访问)。
3)records_estimation阶段,进行访问开销预估。这个阶段是最复杂的。先处理访问类型(explain select_type字段的值),候选项分别为全表扫描和所有的索引,开销最小的那个胜出。如果你的语句有Group By,那么在group_index_range子阶段确定是否有适用于range 访问的索引。
4)considered_execution_plans节显示了选定的执行计划
5)attaching_conditions_to_tables分析where条件是否可以执行pushdown,应该是再扫描该表时过滤掉。
6)clause_processing阶段分别处理group by, order by从句。
下面详细介绍join_optimization的过程:
1)condition_processing阶段,进行where条件处理,分别是相等处理,常量处理,删除冗余条件
2)ref_optimizer_key_uses阶段,查找可进行ref type访问的索引(索引的等值访问)。
3)records_estimation阶段,进行访问开销预估。这个阶段是最复杂的。先处理访问类型(explain select_type字段的值),候选项分别为全表扫描和所有的索引,开销最小的那个胜出。如果你的语句有Group By,那么在group_index_range子阶段确定是否有适用于range 访问的索引。
4)considered_execution_plans节显示了选定的执行计划
5)attaching_conditions_to_tables分析where条件是否可以执行pushdown,应该是再扫描该表时过滤掉。
6)clause_processing阶段分别处理group by, order by从句。
eg:
set optimizer_trace_max_mem_size=300000;
set end_markers_in_json=true;
set optimizer_trace="enabled=on";
mysql> select b from t;
mysql> select trace from information_schema.optimizer_trace\G
*************************** 1. row *************************** trace: { "steps": [ { "join_preparation": { "select#": 1, "steps": [ { "expanded_query": "/* select#1 */ select `t`.`b` AS `b` from `t`" } ] } }, { "join_optimization": { "select#": 1, "steps": [ { "table_dependencies": [ { "table": "`t`", "row_may_be_null": false, "map_bit": 0, "depends_on_map_bits": [ ] } ] }, { "rows_estimation": [ { "table": "`t`", "table_scan": { "rows": 1, "cost": 1 } } ] }, { "considered_execution_plans": [ { "plan_prefix": [ ], "table": "`t`", "best_access_path": { "considered_access_paths": [ { "rows_to_scan": 1, "access_type": "scan", "resulting_rows": 1, "cost": 1.2, "chosen": true } ] }, "condition_filtering_pct": 100, "rows_for_plan": 1, "cost_for_plan": 1.2, "chosen": true } ] }, { "attaching_conditions_to_tables": { "original_condition": null, "attached_conditions_computation": [ ], "attached_conditions_summary": [ { "table": "`t`", "attached": null } ] } }, { "refine_plan": [ { "table": "`t`" } ] } ] } }, { "join_explain": { "select#": 1, "steps": [ ] } } ] } 1 row in set (0.00 sec)
set optimizer_trace="enabled=off";
select trace into dumpfile "json.txt" from information_schema.optimizer_trace;