注:当前测试mysql版本:mysql5.7,编码utf8mb4
trace是MySQL5.6版本后提供的SQL跟踪工具,通过使用trace可以让我们明白optimizer(优化器)如何选择执行计划。
注意:开启trace工具会影响mysql性能,所以只适合临时分析sql使用,用完之后请立即关闭。
测试数据脚本:
DROP TABLE IF EXISTS `t_student`;
CREATE TABLE `t_student` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`std_name` varchar(30) NOT NULL,
`age` tinyint(3) unsigned NOT NULL,
`class_id` int(11) unsigned NOT NULL,
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_std_age` (`age`),
KEY `idx_std_name_age_class` (`std_name`,`age`,`class_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=100766 DEFAULT CHARSET=utf8mb4;
--添加测试数据的存储过程
drop procedure if exists proc_insert_student;
create procedure proc_insert_student()
begin
declare i int;
set i=1;
while(i<=100000)do
insert into t_student(std_name,age,class_id) values(CONCAT('Li Lei',i), (i mod 120)+1 ,(i mod 3)+1);
set i=i+1;
end while;
end;
-- 执行存储过程
call proc_insert_student();
show variables like 'optimizer_trace';
1.会话级别临时开启,只在当前会话生效。
set session optimizer_trace="enabled=on",end_markers_in_json=on;
2.永久开启(重启失效)
注意用完关闭
set optimizer_trace="enabled=on";
在查询sql后加上固定sql,例:
set session optimizer_trace="enabled=on",end_markers_in_json=on;
select * from t_student where std_name > 'a' order by age;
SELECT * FROM information_schema.OPTIMIZER_TRACE;
执行结果:
把TRACE列的json数据拷贝出来查看。
{
"steps": [
{
"join_preparation": { -- 第一阶段:SQL准备阶段,格式化sql
"select#": 1,
"steps": [
{
"expanded_query": "/* select#1 */ select `t_student`.`id` AS `id`,`t_student`.`std_name` AS `std_name`,`t_student`.`age` AS `age`,`t_student`.`class_id` AS `class_id`,`t_student`.`gmt_create` AS `gmt_create` from `t_student` where (`t_student`.`std_name` > 'a') order by `t_student`.`age`"
}
] /* steps */
} /* join_preparation */
},
{
"join_optimization": { -- 第二阶段:SQL优化阶段
"select#": 1,
"steps": [
{
"condition_processing": { -- 条件处理
"condition": "WHERE",
"original_condition": "(`t_student`.`std_name` > 'a')",
"steps": [
{
"transformation": "equality_propagation",
"resulting_condition": "(`t_student`.`std_name` > 'a')"
},
{
"transformation": "constant_propagation",
"resulting_condition": "(`t_student`.`std_name` > 'a')"
},
{
"transformation": "trivial_condition_removal",
"resulting_condition": "(`t_student`.`std_name` > 'a')"
}
] /* steps */
} /* condition_processing */
},
{
"substitute_generated_columns": {
} /* substitute_generated_columns */
},
{
"table_dependencies": [ -- 表依赖详情
{
"table": "`t_student`",
"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": "`t_student`",
"range_analysis": {
"table_scan": { -- 全表扫描
"rows": 100300, -- 行数
"cost": 20351 -- 查询消耗
} /* table_scan */,
"potential_range_indexes": [ -- 查询可能使用的索引
{
"index": "PRIMARY", -- 主键索引
"usable": false, -- 未使用
"cause": "not_applicable" -- 原因:不适合
},
{
"index": "idx_std_age", -- age索引
"usable": false, -- 未使用
"cause": "not_applicable" -- 原因:不适合
},
{
"index": "idx_std_name_age_class", -- stdname,age,class的组合索引
"usable": true, -- 使用
"key_parts": [
"std_name",
"age",
"class_id",
"id"
] /* key_parts */
}
] /* potential_range_indexes */,
"setup_range_conditions": [
] /* setup_range_conditions */,
"group_index_range": { -- group 用到的索引
"chosen": false, -- 未使用
"cause": "not_group_by_or_distinct" -- 原因:未使用group by 或者 distinct
} /* group_index_range */,
"analyzing_range_alternatives": { -- 分析各个索引使用成本
"range_scan_alternatives": [
{
"index": "idx_std_name_age_class",
"ranges": [
"a < std_name" -- 索引使用范围
] /* ranges */,
"index_dives_for_eq_ranges": true,
"rowid_ordered": false, -- 使用该索引获取的记录是否按照主键排序
"using_mrr": false,
"index_only": false, -- 是否使用覆盖索引
"rows": 50150, -- 索引扫描行数
"cost": 60181, -- 索引使用成本
"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": "`t_student`",
"best_access_path": { -- 最优访问路径
"considered_access_paths": [ --分析出的最终访问路径
{
"rows_to_scan": 100300,
"access_type": "scan", -- 访问类型:为scan,全表扫描
"resulting_rows": 100300,
"cost": 20349,
"chosen": true, -- 确定选择
"use_tmp_table": true
}
] /* considered_access_paths */
} /* best_access_path */,
"condition_filtering_pct": 100,
"rows_for_plan": 100300,
"cost_for_plan": 20349,
"sort_cost": 100300,
"new_cost_for_plan": 120649,
"chosen": true
}
] /* considered_execution_plans */
},
{
"attaching_conditions_to_tables": { -- 为查询的表添加条件
"original_condition": "(`t_student`.`std_name` > 'a')",
"attached_conditions_computation": [
] /* attached_conditions_computation */,
"attached_conditions_summary": [ -- 添加条件结果
{
"table": "`t_student`",
"attached": "(`t_student`.`std_name` > 'a')"
}
] /* attached_conditions_summary */
} /* attaching_conditions_to_tables */
},
{
"clause_processing": { -- order by 处理
"clause": "ORDER BY",
"original_clause": "`t_student`.`age`",
"items": [
{
"item": "`t_student`.`age`"
}
] /* items */,
"resulting_clause_is_simple": true,
"resulting_clause": "`t_student`.`age`"
} /* clause_processing */
},
{
"reconsidering_access_paths_for_index_ordering": { -- 重构索引处理顺序
"clause": "ORDER BY",
"steps": [
] /* steps */,
"index_order_summary": {
"table": "`t_student`",
"index_provides_order": false,
"order_direction": "undefined",
"index": "unknown",
"plan_changed": false
} /* index_order_summary */
} /* reconsidering_access_paths_for_index_ordering */
},
{
"refine_plan": [
{
"table": "`t_student`"
}
] /* refine_plan */
}
] /* steps */
} /* join_optimization */
},
{
"join_execution": { -- 第三阶段:SQL执行阶段
"select#": 1,
"steps": [
{
"filesort_information": [
{
"direction": "asc",
"table": "`t_student`",
"field": "age"
}
] /* filesort_information */,
"filesort_priority_queue_optimization": {
"usable": false,
"cause": "not applicable (no LIMIT)"
} /* filesort_priority_queue_optimization */,
"filesort_execution": [
] /* filesort_execution */,
"filesort_summary": {
"rows": 100000,
"examined_rows": 100000,
"number_of_tmp_files": 14,
"sort_buffer_size": 262016,
"sort_mode": ""
} /* filesort_summary */
}
] /* steps */
} /* join_execution */
}
] /* steps */
}