mysql的trace追踪SQL工具,进行sql优化
创始人
2025-01-07 04:02:41
0

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;  DELIMITER $$ 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();

trace工具用法

一.查看trace开关状态,默认关闭的

show variables like 'optimizer_trace';

二.开启face

1.会话级别临时开启,只在当前会话生效。

set session optimizer_trace="enabled=on",end_markers_in_json=on;

2.永久开启(重启失效)

注意用完关闭

set optimizer_trace="enabled=on";

三.用法

1.在查询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;

2.查看执行计划,并未使用到联合索引,联合索引name使用的范围查询,一般都不会用到索引。 如果用name索引需要遍历name字段联合索引树,然后还需要根据遍历出来的主键值去主键索引树里再去查出最终数据,成本比全表扫描还高 。

EXPLAIN SELECT * FROM t_student WHERE std_name > 'a' ORDER BY age;

EXPLAIN SELECT std_name,age,class_id FROM t_student WHERE std_name > 'a' ORDER BY age;

3。如果查询是联合索引字段,那就使用了覆盖索引,这样的name范围查询,联合索引才会使用到,这样只需要遍历name字段的联合索引树就能拿到所有结果,叶子节点只存放二级索引的数据,这就不用回表操作。

TRACE列的json数据拷贝出来查看。主要是看cost值,成本

SELECT * FROM information_schema.OPTIMIZER_TRACE;
{   "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 */ }

MySQL认为 全表扫描的成本低于索引扫描,所以mysql最终选择全表扫描,

4.关闭trace

 set session optimizer_trace="enabled=off";    

相关内容

热门资讯

透视辅助!德州之星有辅助挂&q... 透视辅助!德州之星有辅助挂"扑克时间软件"果然真的有挂(有挂俱乐部)-百度贴吧;1、游戏颠覆性的策略...
黑科技辅助!wpk透视辅助工具... 黑科技辅助!wpk透视辅助工具"wepoke能赢嘛"的确是有挂的(有挂德州)-头条小薇(透视辅助)致...
透视辅助挂!德州之星插件&qu... 透视辅助挂!德州之星插件"weopke真的"就是真的有挂(有挂漏洞)-知乎1、完成weopke真的透...
黑科技辅助挂!wpk透明挂&q... 黑科技辅助挂!wpk透明挂"微扑克ai机器人"一贯真的有挂(有挂渠道)-小红书1、构建自己的微扑克a...
透视辅助!wpk ai辅助&q... 透视辅助!wpk ai辅助"德州ai辅助app"其实真的有挂(有挂苹果版本)-哔哩哔哩1、让任何用户...
黑科技辅助!wepoke辅助德... 黑科技辅助!wepoke辅助德之星"微扑克软件的规律"的确真的有挂(有挂开挂)-微博热搜;微扑克软件...
透明黑科技!wpk外挂&quo... 透明黑科技!wpk外挂"德州ai机器人免费测试"一贯真的有挂(有挂后台)-抖音1、操作简单,无需注册...
黑科技透视!wpk德州透视辅助... 黑科技透视!wpk德州透视辅助"微扑克有辅助"的确真的有挂(有挂苹果版)-知乎1、下载好wpk德州透...
黑科技透视!德州之星插件&qu... 黑科技透视!德州之星插件"aapoker透明挂多久被封"果真真的有挂(有挂app)-今日头条;1、让...
透视辅助挂!wepoke辅助&... 透视辅助挂!wepoke辅助"wpk透视辅助合作"原来真的有挂(有挂靠谱)-小红书;1、很好的工具软...