root@D0DCS 15:17:24 [jing]> show create table t1\G;
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`c1` int(11) NOT NULL DEFAULT '0',
`c2` varchar(128) DEFAULT NULL,
`c3` varchar(64) DEFAULT NULL,
`c4` int(11) DEFAULT NULL,
PRIMARY KEY (`c1`),
KEY `ind_c2` (`c2`),
KEY `ind_c4` (`c4`),
KEY `ind_c2_c4` (`c2`,`c4`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
ERROR:
No query specified
root@D0DCS 15:17:30 [jing]> select * from t1;
+----+------+------+------+
| c1 | c2 | c3 | c4 |
+----+------+------+------+
| 1 | a | A | 10 |
| 2 | b | B | 20 |
| 3 | b | BB | 20 |
| 4 | b | BBB | 30 |
| 5 | b | BBB | 40 |
| 6 | c | C | 50 |
| 7 | d | D | 60 |
+----+------+------+------+
7 rows in set (0.00 sec)
#打开profiling 的设置
SET profiling = 1;
SHOW VARIABLES LIKE '%profiling%';
#查看队列的内容
show profiles;
#来查看统计信息
show profile block io,cpu for query 3;
root@D0DCS 14:46:31 [jing]> explain select * from t1 where c2='b' and c4=20;
+----+-------------+-------+------+-------------------------+--------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-------------------------+--------+---------+-------+------+-------------+
| 1 | SIMPLE | t1 | ref | ind_c2,ind_c4,ind_c2_c4 | ind_c4 | 5 | const | 2 | Using where |
+----+-------------+-------+------+-------------------------+--------+---------+-------+------+-------------+
1 row in set (0.00 sec)
查看查看OPTIMIZER_TRACE方法:
set optimizer_trace="enabled=on";
set optimizer_trace_max_mem_size=1000000;
root@D0DCS 14:47:12 [jing]> set end_markers_in_json=on;
Query OK, 0 rows affected (0.00 sec)
root@D0DCS 14:55:15 [jing]> explain select * from t1 where c2='b' and c4=20;
+----+-------------+-------+------+-------------------------+--------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-------------------------+--------+---------+-------+------+-------------+
| 1 | SIMPLE | t1 | ref | ind_c2,ind_c4,ind_c2_c4 | ind_c4 | 5 | const | 2 | Using where |
+----+-------------+-------+------+-------------------------+--------+---------+-------+------+-------------+
1 row in set (0.00 sec)
root@D0DCS 14:55:44 [jing]> select * from information_schema.optimizer_trace\G;
*************************** 1. row ***************************
QUERY: explain select * from t1 where c2='b' and c4=20
TRACE: {
"steps": [
{
"join_preparation": { ---优化准备工作
"select#": 1,
"steps": [
{
"expanded_query": "/* select#1 */ select `t1`.`c1` AS `c1`,`t1`.`c2` AS `c2`,`t1`.`c3` AS `c3`,`t1`.`c4` AS `c4` from `t1` where ((`t1`.`c2` = 'b') and (`t1`.`c4` = 20))"
}
] /* steps */
} /* join_preparation */
},
{
"join_optimization": { ---优化工作的主要阶段,包括逻辑优化和物理优化两个阶段
"select#": 1,
"steps": [ ---优化工作的主要阶段,逻辑优化阶段
{
"condition_processing": { ---逻辑优化,条件化简
"condition": "WHERE",
"original_condition": "((`t1`.`c2` = 'b') and (`t1`.`c4` = 20))",
"steps": [
{
"transformation": "equality_propagation", --逻辑优化,条件化简,等式处理
"resulting_condition": "((`t1`.`c2` = 'b') and multiple equal(20, `t1`.`c4`))"
},
{
"transformation": "constant_propagation", --逻辑优化,条件化简,常量处理
"resulting_condition": "((`t1`.`c2` = 'b') and multiple equal(20, `t1`.`c4`))"
},
{
"transformation": "trivial_condition_removal", --逻辑优化,条件化简,条件去除
"resulting_condition": "((`t1`.`c2` = 'b') and multiple equal(20, `t1`.`c4`))"
}
] /* 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": [ ---逻辑优化,找出备选的索引
{
"table": "`t1`",
"field": "c2",
"equals": "'b'",
"null_rejecting": false
},
{
"table": "`t1`",
"field": "c4",
"equals": "20",
"null_rejecting": false
},
{
"table": "`t1`",
"field": "c2",
"equals": "'b'",
"null_rejecting": false
},
{
"table": "`t1`",
"field": "c4",
"equals": "20",
"null_rejecting": false
}
] /* ref_optimizer_key_uses */
},
{
"rows_estimation": [ --逻辑优化,估算每个表的元组个数,单表上进行全表扫描和索引扫描的代价估算,每个索引都估算扫描代价
{
"table": "`t1`",
"range_analysis": {
"table_scan": { --逻辑优化, 估算每个表的元组个数. 单表上进行全表扫描的代价
"rows": 7,
"cost": 4.5
} /* table_scan */,
"potential_range_indices": [ ---逻辑优化, 列出备选的索引. 后续版本字符串变为potential_range_ind
{
"index": "PRIMARY", ---逻辑优化, 本行表明主键索引不可用
"usable": false, -- 这个表明这个索引不能用于该语句
"cause": "not_applicable"
},
{
"index": "ind_c2", ---逻辑优化, 索引ind_c2
"usable": true,
"key_parts": [
"c2",
"c1"
] /* key_parts */
},
{
"index": "ind_c4", ---逻辑优化, 索引ind_c4
"usable": true,
"key_parts": [
"c4",
"c1"
] /* key_parts */
},
{
"index": "ind_c2_c4", ---逻辑优化, 索引ind_c2_c4
"usable": true,
"key_parts": [
"c2",
"c4",
"c1"
] /* key_parts */
}
] /* potential_range_indices */,
"setup_range_conditions": [ ---逻辑优化, 如果有可下推的条件,则带条件考虑范围查询
] /* setup_range_conditions */,
"group_index_range": { ---逻辑优化, 如带有GROUPBY或DISTINCT,则考虑是否有索引可优化这种操作. 并考虑带有MIN/MAX的情况
"chosen": false,
"cause": "not_group_by_or_distinct"
} /* group_index_range */,
"analyzing_range_alternatives": { ---逻辑优化,开始计算每个索引做范围扫描的花费(等值比较是范围扫描的特例)
"range_scan_alternatives": [
{
"index": "ind_c2",
"ranges": [
"b <= c2 <= b"
] /* ranges */,
"index_dives_for_eq_ranges": true,
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 4,
"cost": 5.81,
"chosen": false,
"cause": "cost"
},
{
"index": "ind_c4",
"ranges": [
"20 <= c4 <= 20"
] /* ranges */,
"index_dives_for_eq_ranges": true,
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 2,
"cost": 3.41, ---逻辑优化,这个索引的代价最小
"chosen": true ---逻辑优化,这个索引的代价最小,被选中. (比前面的table_scan 和其他索引的代价都小)
},
{
"index": "ind_c2_c4",
"ranges": [
"b <= c2 <= b AND 20 <= c4 <= 20"
] /* ranges */,
"index_dives_for_eq_ranges": true,
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 2,
"cost": 3.41,
"chosen": false,
"cause": "cost"
}
] /* range_scan_alternatives */,
"analyzing_roworder_intersect": {
"intersecting_indices": [
{
"index": "ind_c2_c4",
"index_scan_cost": 1.0476,
"cumulated_index_scan_cost": 1.0476,
"disk_sweep_cost": 1.75,
"cumulated_total_cost": 2.7976,
"usable": true,
"matching_rows_now": 2,
"isect_covering_with_this_index": false,
"chosen": true
},
{
"index": "ind_c4",
"cumulated_total_cost": 2.7976,
"usable": false,
"cause": "does_not_reduce_cost_of_intersect"
},
{
"index": "ind_c2",
"cumulated_total_cost": 2.7976,
"usable": false,
"cause": "does_not_reduce_cost_of_intersect"
}
] /* intersecting_indices */,
"clustered_pk": {
"clustered_pk_added_to_intersect": false,
"cause": "no_clustered_pk_index"
} /* clustered_pk */,
"chosen": false,
"cause": "too_few_indexes_to_merge"
} /* analyzing_roworder_intersect */
} /* analyzing_range_alternatives */, ---逻辑优化,开始计算每个索引做范围扫描的花费. 这项工作结算
"chosen_range_access_summary": { ---逻辑优化,开始计算每个索引做范围扫描的花费. 总结本阶段最优的.
"range_access_plan": {
"type": "range_scan",
"index": "ind_c4",
"rows": 2,
"ranges": [
"20 <= c4 <= 20"
] /* ranges */
} /* range_access_plan */,
"rows_for_plan": 2,
"cost_for_plan": 3.41,
"chosen": true -- 这里看到的cost和rows都比 indx_user 要来的小很多---这个和[A]处是一样的,是信息汇总.
} /* chosen_range_access_summary */
} /* range_analysis */
}
] /* rows_estimation */ ---逻辑优化, 估算每个表的元组个数. 行估算结束
},
{
"considered_execution_plans": [ ---物理优化, 开始多表连接的物理优化计算
{
"plan_prefix": [
] /* plan_prefix */,
"table": "`t1`",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "ref",
"index": "ind_c2",
"rows": 4,
"cost": 2.8,
"chosen": true
},
{
"access_type": "ref", ---物理优化, 计算indx_user索引上使用ref方查找的花费,
"index": "ind_c4",
"rows": 2,
"cost": 2.4,
"chosen": true
},
{
"access_type": "ref",
"index": "ind_c2_c4",
"rows": 2,
"cost": 2.4,
"chosen": false
},
{
"access_type": "range",
"cause": "heuristic_index_cheaper",
"chosen": false
}
] /* considered_access_paths */
} /* best_access_path */,
"cost_for_plan": 2.4,
"rows_for_plan": 2,
"chosen": true
}
] /* considered_execution_plans */
},
{
"attaching_conditions_to_tables": { --逻辑优化,尽量把条件绑定到对应的表上
"original_condition": "((`t1`.`c4` = 20) and (`t1`.`c2` = 'b'))",
"attached_conditions_computation": [
] /* attached_conditions_computation */,
"attached_conditions_summary": [
{
"table": "`t1`",
"attached": "(`t1`.`c2` = 'b')"
}
] /* attached_conditions_summary */
} /* attaching_conditions_to_tables */
},
{
"refine_plan": [
{
"table": "`t1`" ---逻辑优化,下推索引条件"pushed_index_condition";其他条件附加到表上做为过滤条件"table_condition_attached"
}
] /* refine_plan */
}
] /* steps */
} /* join_optimization */ ---逻辑优化和物理优化结束
},
{
"join_explain": {
"select#": 1,
"steps": [
] /* steps */
} /* join_explain */
}
] /* steps */
}
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0
INSUFFICIENT_PRIVILEGES: 0
1 row in set (0.00 sec)
ERROR:
No query specified
上面是比较各个索引的成本,从输出上看, ind_c4 的 cost 是 3.41, ind_c2_c4 的cost也是3.41,
"chosen": true 表明优化器选择了 ind_c4
为什么会选择 ind_c4呢?主要是 ind_c2_c4 的扫描范围更多,
ranges 是 "b <= c2 <= b AND 20 <= c4 <= 20" ,
而 ind_c4 是 "20 <= c4 <= 20"