当前位置:   article > 正文

mysql的trace追踪SQL工具,进行sql优化_mysql trace

mysql trace

trace是MySQL5.6版本后提供的SQL跟踪工具,通过使用trace可以让我们明白optimizer(优化器)如何选择执行计划。

注意:开启trace工具会影响mysql性能,所以只适合临时分析sql使用,用完之后请立即关闭。

测试数据脚本:

  1. DROP TABLE IF EXISTS `t_student`;
  2. CREATE TABLE `t_student` (
  3. `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  4. `std_name` varchar(30) NOT NULL,
  5. `age` tinyint(3) unsigned NOT NULL,
  6. `class_id` int(11) unsigned NOT NULL,
  7. `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  8. PRIMARY KEY (`id`),
  9. KEY `idx_std_age` (`age`),
  10. KEY `idx_std_name_age_class` (`std_name`,`age`,`class_id`) USING BTREE
  11. ) ENGINE=InnoDB AUTO_INCREMENT=100766 DEFAULT CHARSET=utf8mb4;
  12. --添加测试数据的存储过程
  13. DROP PROCEDURE IF EXISTS proc_insert_student;
  14. DELIMITER $$
  15. CREATE PROCEDURE proc_insert_student()
  16. BEGIN
  17. DECLARE i INT;
  18. SET i=1;
  19. WHILE i<=100000 DO
  20. INSERT INTO t_student(std_name,age,class_id) VALUES(CONCAT('Li Lei',i), (i MOD 120)+1 ,(i MOD 3)+1);
  21. SET i=i+1;
  22. END WHILE;
  23. END $$
  24. -- 执行存储过程
  25. 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,例:

  1. set session optimizer_trace="enabled=on",end_markers_in_json=on;
  2. select * from t_student where std_name > 'a' order by age;
  3. 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;
  1. {
  2. "steps": [
  3. {
  4. "join_preparation": { -- 第一阶段:SQL准备阶段,格式化sql
  5. "select#": 1,
  6. "steps": [
  7. {
  8. "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`"
  9. }
  10. ] /* steps */
  11. } /* join_preparation */
  12. },
  13. {
  14. "join_optimization": { -- 第二阶段:SQL优化阶段
  15. "select#": 1,
  16. "steps": [
  17. {
  18. "condition_processing": { -- 条件处理
  19. "condition": "WHERE",
  20. "original_condition": "(`t_student`.`std_name` > 'a')",
  21. "steps": [
  22. {
  23. "transformation": "equality_propagation",
  24. "resulting_condition": "(`t_student`.`std_name` > 'a')"
  25. },
  26. {
  27. "transformation": "constant_propagation",
  28. "resulting_condition": "(`t_student`.`std_name` > 'a')"
  29. },
  30. {
  31. "transformation": "trivial_condition_removal",
  32. "resulting_condition": "(`t_student`.`std_name` > 'a')"
  33. }
  34. ] /* steps */
  35. } /* condition_processing */
  36. },
  37. {
  38. "substitute_generated_columns": {
  39. } /* substitute_generated_columns */
  40. },
  41. {
  42. "table_dependencies": [ -- 表依赖详情
  43. {
  44. "table": "`t_student`",
  45. "row_may_be_null": false,
  46. "map_bit": 0,
  47. "depends_on_map_bits": [
  48. ] /* depends_on_map_bits */
  49. }
  50. ] /* table_dependencies */
  51. },
  52. {
  53. "ref_optimizer_key_uses": [
  54. ] /* ref_optimizer_key_uses */
  55. },
  56. {
  57. "rows_estimation": [ -- 预估表的访问成本
  58. {
  59. "table": "`t_student`",
  60. "range_analysis": {
  61. "table_scan": { -- 全表扫描
  62. "rows": 100300, -- 行数
  63. "cost": 20351 -- 查询消耗
  64. } /* table_scan */,
  65. "potential_range_indexes": [ -- 查询可能使用的索引
  66. {
  67. "index": "PRIMARY", -- 主键索引
  68. "usable": false, -- 未使用
  69. "cause": "not_applicable" -- 原因:不适合
  70. },
  71. {
  72. "index": "idx_std_age", -- age索引
  73. "usable": false, -- 未使用
  74. "cause": "not_applicable" -- 原因:不适合
  75. },
  76. {
  77. "index": "idx_std_name_age_class", -- stdname,age,class的组合索引
  78. "usable": true, -- 使用
  79. "key_parts": [
  80. "std_name",
  81. "age",
  82. "class_id",
  83. "id"
  84. ] /* key_parts */
  85. }
  86. ] /* potential_range_indexes */,
  87. "setup_range_conditions": [
  88. ] /* setup_range_conditions */,
  89. "group_index_range": { -- group 用到的索引
  90. "chosen": false, -- 未使用
  91. "cause": "not_group_by_or_distinct" -- 原因:未使用group by 或者 distinct
  92. } /* group_index_range */,
  93. "analyzing_range_alternatives": { -- 分析各个索引使用成本
  94. "range_scan_alternatives": [
  95. {
  96. "index": "idx_std_name_age_class",
  97. "ranges": [
  98. "a < std_name" -- 索引使用范围
  99. ] /* ranges */,
  100. "index_dives_for_eq_ranges": true,
  101. "rowid_ordered": false, -- 使用该索引获取的记录是否按照主键排序
  102. "using_mrr": false,
  103. "index_only": false, -- 是否使用覆盖索引
  104. "rows": 50150, -- 索引扫描行数
  105. "cost": 60181, -- 索引使用成本
  106. "chosen": false, -- 是否选择该索引:否
  107. "cause": "cost" -- 原因:消耗
  108. }
  109. ] /* range_scan_alternatives */,
  110. "analyzing_roworder_intersect": { -- 分析使用索引合并的成本
  111. "usable": false,
  112. "cause": "too_few_roworder_scans"
  113. } /* analyzing_roworder_intersect */
  114. } /* analyzing_range_alternatives */
  115. } /* range_analysis */
  116. }
  117. ] /* rows_estimation */
  118. },
  119. {
  120. "considered_execution_plans": [ -- 分析出的执行计划
  121. {
  122. "plan_prefix": [
  123. ] /* plan_prefix */,
  124. "table": "`t_student`",
  125. "best_access_path": { -- 最优访问路径
  126. "considered_access_paths": [ --分析出的最终访问路径
  127. {
  128. "rows_to_scan": 100300,
  129. "access_type": "scan", -- 访问类型:为scan,全表扫描
  130. "resulting_rows": 100300,
  131. "cost": 20349,
  132. "chosen": true, -- 确定选择
  133. "use_tmp_table": true
  134. }
  135. ] /* considered_access_paths */
  136. } /* best_access_path */,
  137. "condition_filtering_pct": 100,
  138. "rows_for_plan": 100300,
  139. "cost_for_plan": 20349,
  140. "sort_cost": 100300,
  141. "new_cost_for_plan": 120649,
  142. "chosen": true
  143. }
  144. ] /* considered_execution_plans */
  145. },
  146. {
  147. "attaching_conditions_to_tables": { -- 为查询的表添加条件
  148. "original_condition": "(`t_student`.`std_name` > 'a')",
  149. "attached_conditions_computation": [
  150. ] /* attached_conditions_computation */,
  151. "attached_conditions_summary": [ -- 添加条件结果
  152. {
  153. "table": "`t_student`",
  154. "attached": "(`t_student`.`std_name` > 'a')"
  155. }
  156. ] /* attached_conditions_summary */
  157. } /* attaching_conditions_to_tables */
  158. },
  159. {
  160. "clause_processing": { -- order by 处理
  161. "clause": "ORDER BY",
  162. "original_clause": "`t_student`.`age`",
  163. "items": [
  164. {
  165. "item": "`t_student`.`age`"
  166. }
  167. ] /* items */,
  168. "resulting_clause_is_simple": true,
  169. "resulting_clause": "`t_student`.`age`"
  170. } /* clause_processing */
  171. },
  172. {
  173. "reconsidering_access_paths_for_index_ordering": { -- 重构索引处理顺序
  174. "clause": "ORDER BY",
  175. "steps": [
  176. ] /* steps */,
  177. "index_order_summary": {
  178. "table": "`t_student`",
  179. "index_provides_order": false,
  180. "order_direction": "undefined",
  181. "index": "unknown",
  182. "plan_changed": false
  183. } /* index_order_summary */
  184. } /* reconsidering_access_paths_for_index_ordering */
  185. },
  186. {
  187. "refine_plan": [
  188. {
  189. "table": "`t_student`"
  190. }
  191. ] /* refine_plan */
  192. }
  193. ] /* steps */
  194. } /* join_optimization */
  195. },
  196. {
  197. "join_execution": { -- 第三阶段:SQL执行阶段
  198. "select#": 1,
  199. "steps": [
  200. {
  201. "filesort_information": [
  202. {
  203. "direction": "asc",
  204. "table": "`t_student`",
  205. "field": "age"
  206. }
  207. ] /* filesort_information */,
  208. "filesort_priority_queue_optimization": {
  209. "usable": false,
  210. "cause": "not applicable (no LIMIT)"
  211. } /* filesort_priority_queue_optimization */,
  212. "filesort_execution": [
  213. ] /* filesort_execution */,
  214. "filesort_summary": {
  215. "rows": 100000,
  216. "examined_rows": 100000,
  217. "number_of_tmp_files": 14,
  218. "sort_buffer_size": 262016,
  219. "sort_mode": "<sort_key, packed_additional_fields>"
  220. } /* filesort_summary */
  221. }
  222. ] /* steps */
  223. } /* join_execution */
  224. }
  225. ] /* steps */
  226. }

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

4.关闭trace

 set session optimizer_trace="enabled=off";    

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/608262?site
推荐阅读
相关标签
  

闽ICP备14008679号