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() NOT NULL,
`b` int() DEFAULT NULL,
`c` int() 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
*************************** . row **********************
EXPLAIN: {
"query_block": {
"select_id": ,
"cost_info": {
"query_cost": "1.20"
},
"table": {
"table_name": "t",
"access_type": "index",
"key": "b",
"used_key_parts": [
"b"
],
"key_length": "",
"rows_examined_per_scan": ,
"rows_produced_per_join": ,
"filtered": "100.00",
"using_index": true,
"cost_info": {
"read_cost": "1.00",
"eval_cost": "0.20",
"prefix_cost": "1.20",
"data_read_per_join": ""
},
"used_columns": [
"b"
]
}
}
}
row in set, 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
*************************** . row ***************************
trace: {
"steps": [
{
"join_preparation": {
"select#": ,
"steps": [
{
"expanded_query": "/* select#1 */ select `t`.`b` AS `b` from `t`"
}
]
}
},
{
"join_optimization": {
"select#": ,
"steps": [
{
"table_dependencies": [
{
"table": "`t`",
"row_may_be_null": false,
"map_bit": ,
"depends_on_map_bits": [
]
}
]
},
{
"rows_estimation": [
{
"table": "`t`",
"table_scan": {
"rows": ,
"cost":
}
}
]
},
{
"considered_execution_plans": [
{
"plan_prefix": [
],
"table": "`t`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": ,
"access_type": "scan",
"resulting_rows": ,
"cost": 1.2,
"chosen": true
}
]
},
"condition_filtering_pct": ,
"rows_for_plan": ,
"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#": ,
"steps": [
]
}
}
]
}
row in set (0.00 sec)
set optimizer_trace="enabled=off";
select trace into dumpfile "json.txt" from information_schema.optimizer_trace;