MySQL之SQL分析工具使用
概述:MySQL有三种SQL分析工具,分别为explain、profiling、optimizer_trace,下面分别介绍一下怎么使用的
-
环境
-
MySQL 5.7
-
测试表,随便找个MySQL的表都可以,例:
CREATE TABLE `config` ( `id` int(10) unsigned zerofill NOT NULL AUTO_INCREMENT, `key` varchar(255) NOT NULL DEFAULT '' COMMENT '配置key,唯一', `value` text NOT NULL COMMENT '反馈内容', `type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0 线下,1 线上', `prefix` varchar(50) NOT NULL DEFAULT '' COMMENT '配置前缀,建议和项目名称有关', `create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间', `update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `type_prefix_key` (`type`,`prefix`,`key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='反馈表'
-
-
分析
-
explain 一般用来分析 查询语句
-
使用:
explain SELECT * FROM config where id = 1;
-
结果:
-
各字段含义:参考 MYSQL explain详解
-
id 是select 查询序列号,,查询序列号即为sql语句执行的顺序
-
select_type 是指 select 类型,有以下几种取值
-
simple 简单的select 没有union和子查询
-
primary 在有子查询的语句中,最外面的select 查询就是primary
-
union语句的第二个或者说是后面那一个
-
DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,依赖于外面的查询)
-
UNION RESULT(UNION的结果,union语句中第二个select开始后面所有select)
-
SUBQUERY(子查询中的第一个SELECT,结果不依赖于外部查询)
-
DEPENDENT SUBQUERY(子查询中的第一个SELECT,依赖于外部查询)
-
DERIVED(派生表的SELECT, FROM子句的子查询)
-
UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)
-
-
table输出的行所用的表
-
type 连接类型,下面从最佳类型到最差类型介绍
-
system表示仅有一行,这是const类型的特例,一般不会出现
-
const 表示 只比较primary key或者unique索引且表最多有一行匹配
-
eq_ref 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
-
ref 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
-
range 只检索给定范围的行,使用一个索引来选择行
-
index Full Index Scan,index与ALL区别为index类型只遍历索引树
-
ALL Full Table Scan, MySQL将遍历全表以找到匹配的行
-
-
possible_keys
指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用(该查询可以利用的索引,如果没有任何索引显示 null)
-
key
key列显示MySQL实际决定使用的键(索引),必然包含在possible_keys中
如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
-
key_len
key_len显示的值为索引字段的最大可能长度,即key_len是根据表定义计算而得,不是通过表内检索出的
-
ref
列与索引的比较,表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
-
rows
估算出结果集行数
-
Extra
- Using where:不用读取表中所有信息,仅通过索引就可以获取所需数据
- Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询,常见 group by ; order by
- Using filesort:当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”
- Using join buffer:该值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。
- Impossible where:这个值强调了where语句会导致没有符合条件的行(通过收集统计信息不可能存在结果)。
- Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行
- No tables used:Query语句中使用from dual 或不含任何from子句,关于 dual可以参考:mysql中dual表
-
-
注:
- EXPLAIN没有关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
- EXPLAIN不考虑各种Cache
- EXPLAIN不能显示MySQL在执行查询时所作的优化工作
- 部分统计信息是估算的,并非精确值
-
-
profiling 一般用来分析 查询语句
-
使用
// 开启profiling set profiling=1; // 执行要分析的查询语句 SELECT * FROM config where id = 1; // 获取系统中保存的所有 Query 的 profile 概要信息 show profiles; // 查询资源消耗情况 Duration:SQL语句执行时长 Block_ops_in和Block_ops_out表示块存储设备输入和输出的次数,即从硬盘读取和写入数据的次数 show profile for query queryid; show profile cpu, block, io for query queryid; // 关闭profiling SET profiling = 0;
-
-
optimizer_trace
-
支持操作
SELECT、INSERT、REPLACE、UPDATE、DELETE、EXPLAIN、SET、DECLARE、CASE、IF、RETURN、CALL
-
使用
// enabled:optimizer_trace、one_line:是否开启单行存储。 set optimizer_trace="enabled=on,one_line=off"; // 查看optimizer_trace配置 show variables like '%optimizer_trace%'; //默认情况下,由于optimizer_trace_offset=-1,optimizer_trace_limit=1,记录最近的一条SQL语句,展示时,每次展示1条数据; // 如果改成 SET optimizer_trace_offset=-2, optimizer_trace_limit=1 ,则会记录倒数第二条SQL语句; //Maximum allowed cumulated size of stored optimizer traces 单位字节 SET OPTIMIZER_TRACE_MAX_MEM_SIZE=1000000 // 查找结果 select * from information_schema.optimizer_trace; //OPTIMIZER_TRACE结果分析 //QUERY:查询语句 //TRACE:QUERY字段对应语句的跟踪信息 //MISSING_BYTES_BEYOND_MAX_MEM_SIZE:跟踪信息过长时,被截断的跟踪信息的字节数。 //INSUFFICIENT_PRIVILEGES:执行跟踪语句的用户是否有查看对象的权限。当不具有权限时,该列信息为1且TRACE字段为空,一般在调用带有SQL SECURITY DEFINER的视图或者是存储过程的情况下,会出现此问题。 // 主要对trace的内容进行分析
-
结果分析:
{ "steps": [ { "join_preparation": { "select#": 1, "steps": [ { // 格式化SQL "expanded_query": "/* select#1 */ select `config`.`id` AS `id`,`config`.`key` AS `key`,`config`.`value` AS `value`,`config`.`type` AS `type`,`config`.`prefix` AS `prefix`,`config`.`create_time` AS `create_time`,`config`.`update_time` AS `update_time` from `config` where (`config`.`id` = 1) limit 0,5000" } ] } }, { // 优化阶段的执行过程 "join_optimization": { "select#": 1, "steps": [ { // 对条件处理,主要对WHERE条件进行优化处理 "condition_processing": { // 优化对象类型。WHERE条件句或者是HAVING条件句 "condition": "WHERE", // 优化前的原始语句 "original_condition": "(`config`.`id` = 1)", "steps": [ { // 转换类型句 "transformation": "equality_propagation", //转换之后的结果输出 "resulting_condition": "multiple equal(1, `config`.`id`)" }, { "transformation": "constant_propagation", "resulting_condition": "multiple equal(1, `config`.`id`)" }, { "transformation": "trivial_condition_removal", "resulting_condition": "multiple equal(1, `config`.`id`)" } ] } }, { // 用于替换虚拟生成列 "substitute_generated_columns": {} }, { //分析表之间的依赖关系 "table_dependencies": [ { // 涉及的表名 "table": "`config`", //行是否可能为NULL,这里是指JOIN操作之后,这张表里的数据是不是可能为NULL。如果语句中使用了LEFT JOIN,则后一张表的row_may_be_null会显示为true "row_may_be_null": false, //表的映射编号,从0开始递增 "map_bit": 0, //依赖的映射表。主要是当使用STRAIGHT_JOIN强行控制连接顺序或者LEFT JOIN/RIGHT JOIN有顺序差别时,会在depends_on_map_bits中展示前置表的map_bit值 "depends_on_map_bits": [] } ] }, { //列出所有可用的ref类型的索引。如果使用了组合索引的多个部分,则会在ref_optimizer_key_uses下列出多个元素,每个元素中会列出ref使用的索引及对应值。 "ref_optimizer_key_uses": [ { "table": "`config`", "field": "id", "equals": "1", "null_rejecting": false } ] }, { //用于估算需要扫描的记录数。 "rows_estimation": [ { "table": "`config`", "rows": 1, "cost": 1, "table_type": "const", "empty": false } ] }, { "condition_on_constant_tables": "1", "condition_value": true }, { "attaching_conditions_to_tables": { "original_condition": "1", "attached_conditions_computation": [], "attached_conditions_summary": [] } }, { //改善执行计划 "refine_plan": [] } ] } }, { // 执行阶段的执行过程 "join_execution": { "select#": 1, "steps": [] } } ] }
注:本文所举例子过于简单,有些情况没有覆盖到,更详细的对trace的内容分析,可参考用MySQL的optimizer_trace进行sql调优、mysql optimizertrace_MySQL 调优 | OPTIMIZER_TRACE详解
-
-
注: