若想查看MySQL优化器优化后的sql语句可使用以下语句:html
EXPLAIN EXTENDED sql_statement; -- show warnings紧接着上面的语句执行 SHOW WARNINGS\G;
Explain输出字段:mysql
Column | 含义 |
---|---|
id | 查询序号 |
select_type | 查询类型 |
table | 表名 |
partitions | 匹配的分区 |
type | join类型 |
prossible_keys | 可能会选择的索引 |
key | 实际选择的索引 |
key_len | 索引的长度 |
ref | 与索引做比较的列 |
rows | 要检索的行数(估算值) |
filtered | 查询条件过滤的行数的百分比 |
Extra | 额外信息 |
select的标识符。整个查询语句中每一个select的序列号。id越大的SELECT最早被执行,对于id相同的记录,顺序由上往下。若此行引用的是其余行UNION的结果,则id值为NULL。算法
查询类型,包含如下几种:sql
select_type | 类型说明 |
---|---|
SIMPLE | 简单SELECT(不使用UNION或子查询) |
PRIMARY | 最外层的SELECT |
UNION | UNION中第二个或以后的SELECT语句 |
DEPENDENT UNION | UNION中第二个或以后的SELECT语句取决于外面的查询 |
UNION RESULT | UNION的结果 |
SUBQUERY | 子查询中的第一个SELECT |
DEPENDENT SUBQUERY | 子查询中的第一个SELECT, 取决于外面的查询 |
DERIVED | 衍生表(FROM子句中的子查询) |
MATERIALIZED | 物化子查询 |
UNCACHEABLE SUBQUERY | 结果集没法缓存的子查询,必须从新评估外部查询的每一行 |
UNCACHEABLE UNION | UNION中第二个或以后的SELECT,属于没法缓存的子查询 |
DEPENDENT 意味着使用了关联子查询。关于关联子查询查看:Correlated Subqueries缓存
输出行所引用的表。也能够为以下的值:session
此查询匹配到的分区。只有在PARTITIONS关键字被使用的时候此字段会显示。若表没有分区则值为NULL。函数
联接类型,下面详细介绍各类join类型,顺序为从最优类型到最差类型:oop
表中只有一行数据(= system table)。这是const类型的一个特例。性能
最多只有一行记录匹配,它将在查询开始时被读取。因为仅有一行记录匹配,因此此条记录的列值可被优化器视为常数。由于只读取一次,因此const表很快。优化
当联合主键或惟一索引的全部字段
跟常量值比较时,join类型为const。在下面的查询中,tlb_name能够被用做const表:
SELECT * FROM tbl_name WHERE primary_key=1; SELECT * FROM tbl_name WHERE unique_key=1; SELECT * FROM tbl_name WHERE primary_key_part1=1 AND primary_key_part2=2;
多表join时,对于来自前面表的每一行,在当前表中只能找到一行
。这多是除了system和const以外最好的类型。当主键或惟一非NULL索引的全部字段都被用做join联接时会使用此类型。
eq_ref可用于使用'='操做符做比较的索引列。比较的值能够是常量,也能够是使用在此表以前读取的表的列的表达式。在下面的例子中,MySQL可以使用eq_ref类型来处理ref_table:
SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column; SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;
对于来自前面表的每一行,在此表的索引中能够匹配到多行
。若联接只用到索引的最左前缀或索引不是主键或惟一索引时,使用ref类型(也就是说,此联接可以匹配多行记录)。
ref可用于使用'='或'<=>'操做符做比较的索引列。在下面的例子中,MySQL使用ref类型来处理ref_table:
SELECT * FROM ref_table WHERE key_column=expr; SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column; SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;
在用到全文索引时会使用此类型。
除了MySQL会额外查询包含NULL值的行,此类型跟ref同样。此类型经常使用在解析子查询的时候。在以下的例子中,MySQL使用ref_or_null类型:
SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
表示使用了索引合并优化。在这种状况下,key列包含了使用的索引的列表,key_len列包含了使用的索引的最长部分的列表。更多信息:Index Merge Optimization
对于以下形式的IN子查询,使用此类型替换eq_ref类型:
value IN (SELECT primary_key FROM single_table WHERE some_expr)
unique_subquery 仅是一个索引查找功能,可以以更高的效率彻底替换子查询。
跟unique_subquery相似。能够替代IN子查询,可是它适用于以下形式子查询中的非惟一索引:
value IN (SELECT key_column FROM single_table WHERE some_expr)
使用索引查询记录,只取回指定范围的行。key列显示使用了哪一个索引,key_len列包含了使用了此索引的长度。此类型下的ref列值为NULL。
当索引列使用=, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN()操做符与常量做比较时,会用到range类型。
SELECT * FROM tbl_name WHERE key_column = 10; SELECT * FROM tbl_name WHERE key_column BETWEEN 10 and 20; SELECT * FROM tbl_name WHERE key_column IN (10,20,30); SELECT * FROM tbl_name WHERE key_part1 = 10 AND key_part2 IN (10,20,30);
除了扫描的是索引树,此类型跟ALL类型相同。
若此索引对于查询来讲为覆盖索引,而且仅经过扫描索引树
就能获得查询所需的数据。这种状况下,Extra列会显示_Using index_。仅扫描索引树比ALL类型更快的缘由:索引数据一般比表的数据小。
当只查询索引中的部分字段时,MySQL可使用此联接类型。
CREATE TABLE `store_location` ( `store_id` int(11) NOT NULL DEFAULT '0', `store_name` varchar(30) DEFAULT NULL, `province_id` int(11) DEFAULT NULL, `city_id` int(11) DEFAULT NULL, `district_id` int(11) DEFAULT NULL, PRIMARY KEY (`store_id`), KEY `idx_location` (`province_id`,`city_id`,`district_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 insert into store_location values(1,'adidas',110,230,560); insert into store_location values(2,'nike',111,231,561); insert into store_location values(3,'new banlace',112,232,562); insert into store_location values(4,'puma',113,233,563); mysql> explain select province_id,city_id,district_id from store_location where city_id > 231; +----+-------------+----------------+-------+---------------+--------------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------------+-------+---------------+--------------+---------+------+------+--------------------------+ | 1 | SIMPLE | store_location | index | NULL | idx_location | 15 | NULL | 4 | Using where; Using index | +----+-------------+----------------+-------+---------------+--------------+---------+------+------+--------------------------+ 1 row in set (0.00 sec)
即全表扫面,性能最差。能够经过适当添加索引来避免出现ALL。
指出MySQL可使用哪些索引从表中查询记录。这些索引没有优先级之分。
若是该列为NULL,则没有相应的索引。在这种状况下,须要检查WHERE条件引用的字段是否加上了合适的索引。若是没有创建合适的索引,建立适当的索引并使用explain来评估此查询。
能够经过 SHOW INDEX FROM table_name
查看表中的索引。
MySQL实际使用的索引。key的取值也可能不在prossible_keys中。
经过在语句中使用 FORCE INDEX, USE INDEX, or IGNORE INDEX 来强制MySQL使用或忽略一个索引。详情查看:Index Hints
被选中的索引的长度(单位:Byte)。若key列为NULL,则key列值为NULL。注意:经过key_len的值能够肯定实际使用了联合索引的哪些部分。
关于key_len值的计算,能够查看此文章:http://imysql.com/2015/10/20/mysql-faq-key-len-in-explain.shtml
使用哪些列或常量跟key的值做比较来查询记录。若值为func,那么此值使用的是函数的结果。在EXPLAIN EXTENDED 语句以后使用 SHOW WARNINGS 能够查看使用的是哪一个函数。
执行查询时须要检查的行数。对于InnoDB表,这是一个估算值,结果可能并不许确。
查询条件过滤了表中多少行记录,是一个估算的百分比值。rows列显示的是行数的估算值,rows × filtered / 100 表示跟前面表做join的行数。此列只有在使用EXPLAIN EXTENDED时才会展现。
解析查询语句时的额外信息,以下:
MySQL须要额外的排序操做,以按顺序返回数据。详情查看: ORDER BY Optimization
只需从索引树中返回所需字段的信息,而不须要额外从磁盘读取实际数据。当查询仅需返回单个索引中部分字段时,Extra字段显示此信息。
跟 Using index 访问方式相似,MySQL能够从索引中取回GROUP BY或DISTINCT查询所需的数据,而不须要额外从磁盘读取实际数据。详情查看: GROUP BY Optimization
使用了Index Condition Pushdown优化,详情查看: Index Condition Pushdown Optimization
将join前面的表的一部分放到join buffer中,而后用buffer中的记录跟当前表执行join操做。(Block Nested Loop) 表示使用Block Nested-Loop算法,(Batched Key Access) 表示使用Batched Key Access算法。就是说,前面的key列中出现的字段会放到join buffer中,而后从出现 Using join buffer 的那一行table字段列出的表中分批取回匹配的行。
使用了Multi-Range Read优化策略,详情查看: Multi-Range Read Optimization
对于type值为index_merge类型的联接,使用了哪一种索引合并算法。关于索引合并优化能够查看: Index Merge Optimization
为了处理查询,须要建立临时表保存结果。若是查询语句包含GROUP BY和ORDER BY而且列出的字段不同,Extra会出现此信息。
WHERE子句用于限制返回给客户端或与下一个表匹配的记录。除非你确实想要获取或检查表的全部行,不然查询会有问题若Extra不包含Using where而且联接类型为ALL或index。
SHOW PROFILE
和 SHOW PROFILES
能够查看在当前session中查询语句的资源使用状况的分析信息。 SHOW PROFILE句法格式:
SHOW PROFILE [type [, type] ... ] [FOR QUERY n] [LIMIT row_count [OFFSET offset]] type: ALL | BLOCK IO | CONTEXT SWITCHES | CPU | IPC | MEMORY | PAGE FAULTS | SOURCE | SWAPS
Profiling功能能够经过session变量来控制,默认值为0(OFF)。能够经过以下语句设置为开启状态:
mysql> SET profiling = 1;
SHOW PROFILES 语句能够查看当前session中最近执行的语句的一个列表。此列表的大小经过session变量 profiling_history_size
设置,默认值为15,最大值为100。将此变量设置为0至关于禁用Profiling。
SHOW PROFILE 语句能够查看一条sql语句的详细信息。若不包含 FOR QUERY n 子句,输出的是最近一条语句的信息。加上 FOR QUERY n
后 SHOW PROFILE
显示语句n的信息。
更多关于profiling的信息,查看MySQL官网:SHOW PROFILE Syntax
以下代码为使用profiling的例子:
mysql> SET profiling = 1; Query OK, 0 rows affected (0.00 sec) mysql> select * from test_c where b = 1; +---+------+ | a | b | +---+------+ | 1 | 1 | +---+------+ 1 row in set (0.02 sec) mysql> select * from test_d where b = 1; +---+------+------+------+ | a | b | c | d | +---+------+------+------+ | 1 | 1 | 1 | 111 | | 5 | 1 | 1 | 511 | +---+------+------+------+ 2 rows in set (0.03 sec) mysql> show profiles; +----------+------------+----------------------------------+ | Query_ID | Duration | Query | +----------+------------+----------------------------------+ | 1 | 0.01119375 | select * from test_c where b = 1 | | 2 | 0.02607875 | select * from test_d where b = 1 | +----------+------------+----------------------------------+ mysql> show profile for query 2; +----------------------+----------+ | Status | Duration | +----------------------+----------+ | starting | 0.000121 | | checking permissions | 0.000033 | | Opening tables | 0.000041 | | init | 0.000048 | | System lock | 0.000035 | | optimizing | 0.000039 | | statistics | 0.014997 | | preparing | 0.000046 | | executing | 0.000024 | | Sending data | 0.010304 | | end | 0.000042 | | query end | 0.000025 | | closing tables | 0.000028 | | freeing items | 0.000059 | | cleaning up | 0.000239 | +----------------------+----------+ 15 rows in set, 1 warning (0.01 sec) mysql> show profile cpu,block io for query 8; +----------------------+----------+----------+------------+--------------+---------------+ | Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | +----------------------+----------+----------+------------+--------------+---------------+ | starting | 0.000121 | 0.000000 | 0.000000 | 0 | 0 | | checking permissions | 0.000033 | 0.000000 | 0.000000 | 0 | 0 | | Opening tables | 0.000041 | 0.000000 | 0.000000 | 0 | 0 | | init | 0.000048 | 0.000000 | 0.000000 | 0 | 0 | | System lock | 0.000035 | 0.000000 | 0.000000 | 0 | 0 | | optimizing | 0.000039 | 0.000000 | 0.000000 | 0 | 0 | | statistics | 0.014997 | 0.000999 | 0.000000 | 128 | 0 | | preparing | 0.000046 | 0.000000 | 0.000000 | 0 | 0 | | executing | 0.000024 | 0.000000 | 0.000000 | 0 | 0 | | Sending data | 0.010304 | 0.000000 | 0.000000 | 0 | 0 | | end | 0.000042 | 0.000000 | 0.000000 | 0 | 0 | | query end | 0.000025 | 0.000000 | 0.000000 | 0 | 0 | | closing tables | 0.000028 | 0.000000 | 0.000000 | 0 | 0 | | freeing items | 0.000059 | 0.000000 | 0.000000 | 0 | 0 | | cleaning up | 0.000239 | 0.000000 | 0.000000 | 0 | 0 | +----------------------+----------+----------+------------+--------------+---------------+ 15 rows in set, 1 warning (0.00 sec) -- 最后关闭profiling mysql> set profiling = 0; Query OK, 0 rows affected, 1 warning (0.01 sec)
参考: