一 建表和现象的过程如下

CREATE TABLE t1 (id1 INT, a1 INT, b1 INT, PRIMARY KEY(id1));
CREATE TABLE t3 (id3 INT UNIQUE, a3 INT, b3 INT);

INSERT INTO t1 VALUES (1, 1, NULL);
INSERT INTO t3 VALUES (1, 1, NULL);

mysql> select * from (select * from t1 where id1 =(select id3 from t3 where id3=1)) t;
+-----+------+------+
| id1 | a1 | b1 |
+-----+------+------+
| 1 | 1 | NULL |
+-----+------+------+
1 row in set (0.01 sec)

mysql> explain extended select * from (select * from t1 where id1=(select id3 from t3 where id3=1)) t;
+----+-------------+------------+--------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+----------+-------------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | 100.00 | NULL |
| 2 | DERIVED | t1 | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
| 3 | SUBQUERY | t3 | const | id3 | id3 | 5 | const | 1 | 100.00 | Using index |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)

mysql> show warnings;
+-------+------+-----------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+-----------------------------------------------------------------------+
| Note | 1003 | /* select#1 */ select '1' AS `id1`,'1' AS `a1`,NULL AS `b1` from dual |
+-------+------+-----------------------------------------------------------------------+
1 row in set (0.00 sec)


二 分析:
首先, 察看执行计划:
1 id值为1的select_type值为PRIMARY, 这是一个'<derived2>'表,表示子查询出现在FROM子句中,且本行的内容是一个类似“壳”一样的并无多大实质意义的‘虚表’,'<derived2>'中的数字2来自于下一行id为2的结果。而别名为t的子查询,确实出现在最外层的FROM中。
2 id值为2的select_type值为DERIVED,表示这是一个被驱动的表(被驱动的FROM子句中的子查询). 
3 id值为3的select_type值为SUBQUERY,表示嵌套中的第二个在t3表上的子查询,没有被优化为其他类型(优化可如子查询被消除后转为内连接)。

其次,察看警告信息:
1 FROM子句后的表变为了‘dual’这一虚表,t1和t2全部消失。为什么?
2 MySQL在优化的过程中,利用等式的性质,推知了:
  2.1 id1=id3=1
  2.2 查询语句从逻辑推理上,就可以变形为:select * from t1 where id1=1
      此时,子查询其实被消除了,但是执行计划中没有体现这一点,这是执行计划错误之处。
  2.3 进一步,t1表上id1列是主键,所以根据索引,可以查知*对应的目标列的值:这样,逻辑推理上,就可以变形为:
      select '1' AS `id1`,'1' AS `a1`,NULL AS `b1` from t1 where id1=1
  2.4 因为目标列的值已经能够在优化的过程中得知,所以FROM子句中的表,可被标识为“常量表”。
3 于是,在显示查询执行计划的后期(explain命令后期),代码中有个判断:如果表全部是常量表且已经是“被优化了的(optimized_away)”则把FROM子句中的表对象,用“dual”替换。这就是警告中为什么会出现“from dual”的原因。

再次,执行计划和警告信息显示存在不一致,那么,MySQL在执行的时候,是按照谁来执行呢?
这点可以通过跟踪代码进行分析。
执行过程如下:
1 优化阶段:即生成执行计划阶段

  MySQL在优化阶段的过程,就如执行计划显示的结果一样,对各个子句进行着执行计划显示的过程,先是因为FROM子句中的子查询执行id为1的过程,然后是对被驱动的id为2的优化,在没有结束id为2的优化的过程中,发现id为2的子句是子查询,就嵌套调用去优化子查询,于是引发了等式化简等过程。
  在运用各种技术做各种化简的过程中,一些值或结果已经得知,顺带即完成了一些求解的工作。
  这也说明一个问题:有的朋友问id间的序号表明了一个什么样的执行次序?因为嵌套的关系,首先启动的是id值小的,在id值为小的执行过程中,接着又启动了id值为大的查询子句,所以,最先执行完毕的,是id值大者;最先执行的,是id值小者。
2 执行阶段: 
  已经知道是一个常量求解,且结果在优化过程中得知,直接输出。
  这也解释了警告信息中得到的是“from dual”,与执行过程的含义,相符。即:执行阶段,查询计划表明的过程已经结束了。

三 补充说明

mysql>  explain extended select * from (select * from t1 where id1 in (select id3 from t3 where id3=1)) t;
    -> ;
+----+-------------+------------+--------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | PRIMARY     | <derived2> | system | NULL          | NULL    | NULL    | NULL  |    1 |   100.00 | NULL        |
|  2 | DERIVED     | t1         | const  | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL        |
|  2 | DERIVED     | t3         | const  | id3           | id3     | 5       | const |    1 |   100.00 | Using index |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+----------+-------------+
3 rows in set, 1 warning (49.53 sec)

mysql> show warnings;
+-------+------+-----------------------------------------------------------------------+
| Level | Code | Message                                                               |
+-------+------+-----------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select '1' AS `id1`,'1' AS `a1`,NULL AS `b1` from dual |
+-------+------+-----------------------------------------------------------------------+
1 row in set (0.00 sec)

"标题三"中和"标题一"中的SQL差别在于嵌套的子查询的形式是等号还是IN。

而IN的形式,被MySQL识别优化了标识子查询未“DERIVED ”了,这是MySQL从形式上目前只支持IN形式的子查询优化的优化,对于等号这样的形式,不支持。但是,从等式性质上,最终对"标题一"中的SQL进行了优化。

参考:

http://blog.163.com/li_hx/blog/static/18399141320146219354154/

MySQL执行计划显示与执行过程不符合一例的更多相关文章

  1. ORACLE实际执行计划与预估执行计划不一致性能优化案例

      在一台ORACLE服务器上做巡检时,使用下面SQL找出DISK_READ最高的TOP SQL分析时,分析过程中,有一条SQL语句的一些反常现象,让人觉得很奇怪: SELECT SQL_ID,    ...

  2. xplan.sql(本脚本获取执行计划显示执行顺序)

    -- ---------------------------------------------------------------------------------------------- -- ...

  3. MySQL执行计划解析

    前言 在实际数据库项目开发中,由于我们不知道实际查询时数据库里发生了什么,也不知道数据库是如何扫描表.如何使用索引的,因此,我们能感知到的就只有SQL语句的执行时间.尤其在数据规模比较大的场景下,如何 ...

  4. MYSQL与TiDB的执行计划

    前言 这里采用了tpc-h一个数据库的数据量来进行查询计划的对比.并借助tpc-h中的22条查询语句进行执行计划分析. mysql采用的是标准安装,TiDB采用的是单机测试版,这里的性能结果不能说明其 ...

  5. 读懂MySQL执行计划

    原文:https://mp.weixin.qq.com/s/-BlLvBKcF-yalELY7XkqaQ 前言 在之前的面试过程中,问到执行计划,有很多童鞋不知道是什么?甚至将执行计划与执行时间认为是 ...

  6. MySQL执行计划分析

    原文:MySQL执行计划分析 一. 执行计划能告诉我们什么? SQL如何使用索引 联接查询的执行顺序 查询扫描的数据函数 二. 执行计划中的内容 SQL执行计划的输出可能为多行,每一行代表对一个数据库 ...

  7. 高性能可扩展mysql 笔记(六) SQL执行计划及分页查询优化、分区键统计

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 常见业务处理 一.使用数据库处理常见业务: 案例: 如何对评论进行分页展示 使用 EXPLAIN 获得s ...

  8. mysql之优化器、执行计划、简单优化

    mysql之优化器.执行计划.简单优化 2018-12-12 15:11 烟雨楼人 阅读(794) 评论(0) 编辑 收藏 引用连接: https://blog.csdn.net/DrDanger/a ...

  9. MySQL 查看执行计划

    MySQL 使用 explain + sql 语句查看 执行计划,该执行计划不一定完全正确但是可以参考. EXPLAIN SELECT * FROM user WHERE nid = 3; selec ...

随机推荐

  1. ACM - 动态规划专题 题目整理

    CodeForces 429B  Working out 预处理出从四个顶点到某个位置的最大权值,再枚举相遇点,相遇的时候只有两种情况,取最优解即可. #include<iostream> ...

  2. 中文Ubuntu系统根目录文件夹名称变为英文

    Ubuntu中文安装后,家目录均为中文,如“下载” “文档”等等,在使用Shell时很不方便,可用如下方法将这些文件夹名称改回英文 1.使用命令 export LANG=en_US xdg-user- ...

  3. php大力力 [012节]PHP连接mySQL数据库

    php大力力 [012节]PHP连接mySQL数据库 1.用简单的php测试代码,而不是直接进入前端页面,越简单越好 2.在=号前后,不要写空格,万一写了中文空格,排除错误很麻烦. 3.我在mysql ...

  4. HDOJ-三部曲一(搜索、数学)-1010-Pots

    Pots Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) Total Submiss ...

  5. 三色二叉树_树形DP

    Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description 一棵二叉树可以按照如下规则表示成一个由0.1.2组成的字符序 ...

  6. 【转】利用 Bootstrap 进行快速 Web 开发

    原文转自:http://blog.jobbole.com/53961/ 了解如何使用 Bootstrap 快速开发网站和 Web 应用程序(包括移动友好型应用程序).Bootstrap 以 LESS ...

  7. lua元表和元方法 《lua程序设计》 13章 读书笔记

    lua中每个值都有一个元表,talble和userdata可以有各自独立的元表,而其它类型的值则共享其类型所属的单一元表.lua在创建table时不会创建元表. t = {} print(getmet ...

  8. 【题解】【字符串】【BFS】【Leetcode】Word Ladder

    Given two words (start and end), and a dictionary, find the length of shortest transformation sequen ...

  9. sass中mixin常用的CSS3

    圆角border-radius @mixin rounded($radius){ -webkit-border-radius: $radius; -moz-border-radius: $radius ...

  10. java NIO-我们到底能走多远系列(39)

    献给各位: Satisfied MindRed Hayes and Jack RhodesHow many times have you heard someone say,"If I ha ...