EXPLAIN:id字段详解
EXPLAIN:id字段详解
前文链接: MySQL性能分析工具的使用:EXPLAIN的概述及各列的作用
我们写的查询语句一般都以 SELECT 关键字开头,比较简单的查询语句里只有一个 SELECT 关键字,比如下边这个查询语句:
SELECT * FROM s1 WHERE key1 = 'a';
但是下边两种情况下在一条查询语句中会出现多个SELECT关键字:
查询中包含子查询
SELECT * FROM s1 WHERE key1 IN (SELECT key3 FROM s2);
查询中包含UNION语句
SELECT * FROM s1 UNION SELECT * FROM s2;
查询语句中每出现一个SELECT关键字,MySQL就会为它分配一个唯一的id值。这个id值就是EXPLAIN语句的
第一个列,比如下边这个查询中只有一个SELECT关键字,所以EXPLAIN的结果中也就只有一条id列为1的记
录:id相同
EXPLAIN SELECT * FROM s1 WHERE key1 = 'a'
对于连接查询来说,一个SELECT关键字后边的FROM字句中可以跟随多个表,所以在连接查询的执行计 划中,每个表都会对应一条记录,但是这些记录的id值都是相同的,比如:
EXPLAIN SELECT * FROM s1 INNER JOIN s2;
可以看到,上述连接查询中参与连接的s1和s2表分别对应一条记录,但是这两条记录对应的id都是1。这里需要大家记住的是,在连接查询的执行计划中,每个表都会对应一条记录,这些记录的id列的值是相同的,出现在前边的表表示驱动表,出现在后面的表表示被驱动表。所以从上边的EXPLAIN输出中我 们可以看到,查询优化器准备让s1表作为驱动表,让s2表作为被驱动表来执行查询
。
id不同
对于包含子查询的查询语句来说,就可能涉及多个 SELECT 关键字,所以在包含子查询的查询语句的执行计划中,每个 SELECT 关键字都会对应一个唯一的id值,比如这样:EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'a';
从输出结果中我们可以看到s1表在外层查询中,外层查询有一个独立的SELECT关键字,所以第一条记录的id
值就是1,s2表在子查询中,子查询有一个独立的SELECT关键字,所以第二条记录的id值就是2。
`但是这里大家需要特别注意,查询优化器可能对涉及子查询的查询语句进行重写,从而转换为连接查询。所以如
果我们想知道查询优化器对某个包含子查询的语句是否进行了重写,直接查看执行计划就好了,比如说:`
# 查询优化器可能对涉及子查询的查询语句进行重写,转变为多表查询的操作。
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key2 FROM s2 WHERE
common_field = 'a');
这个语句的执行计划的第三条记录是什么?为何id值是NULL,而且table列也很奇怪?UNI0N!
它会把多个查询的结果集合并起来并对结果集中的记录进行去重,怎么去重呢?MySQL使用的是内部的临时表。正如上边的查询计划中所示,UNION子句是为了把id为1的查询和id为2的查询的结果集合并起来并去重,所以在内部创建了一个名为<union1,2>的临时表(就是执行计划第三条记录的table列的名称),id为NULL表明这个临时表是为了合并两个查询的结果集而创建的。
跟UNION对比起来,UNION ALL就不需要为最终的结果集进行去重,它只是单纯的把多个查询的结果集中的记录合并成,一个并返回给用户,所以也就不需要使用临时表。所以在包含UNION ALL子句的查询的执行计划中,就没有那个id为NULL的记录,如下所示:
EXPLAIN SELECT * FROM s1 UNION ALL SELECT * FROM s2;
- 小结
- id如果相同,可以认为是一组,从上往下顺序执行
- 在所有组中,id值越大,优先级越高,越先执行
- id号每个号码,表示一趟独立的查询, 一个sql的查询趟数越少越好