本文将通过演示告诉你:MySQL中派生表(Derived Table)是什么?以及MySQL对它的优化。

Background

有如下一张表:

mysql> desc city;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| country | varchar(40) | YES | | NULL | |
| population | int(11) | YES | | NULL | |
| city | varchar(40) | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+

例如,如果首先考虑选择人口超过10,000人的城市,然后选择那些位于德国的城市,那么可以写这个SQL:

SELECT *
FROM
(SELECT * FROM city WHERE population > 10*1000) AS big_city
WHERE
big_city.country='Germany';

使用 EXPLAIN 命令查看执行计划:

mysql> EXPLAIN SELECT * FROM (SELECT * FROM city WHERE population > 1*1000) AS big_city WHERE big_city.country='Germany' ;
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 4068 | Using where |
| 2 | DERIVED | City | ALL | Population | NULL | NULL | NULL | 4079 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
2 rows in set (0.60 sec)

注意:mysql 5.7 需要设置 derived_merge=off,才会有上面的结果。否则MySQL会把临时表合并到外层查询,具体可参见我的另一篇文章《MySQL中的两种临时表》。

MySQL 的做法是:

经历如下3个步骤:

  1. 执行子查询:(SELECT * FROM city WHERE population > 1*1000),正如查询语句中的那样;
  2. 把子查询的结果写到临时表 big_city ;
  3. 回读,应用上层SELECT的WHERE条件 big_city.country='Germany' 。

执行这样的子查询是非常低效的,因为扫描基表 city 时没有使用父选择(country ='Germany')的高选择性条件。 我们从City表中读取太多记录,然后我们必须将它们写入一个临时表并再次读取,然后才能过滤掉它们。

Derived table merge in action

如果在MariaDB / MySQL 5.6中运行此查询,则可以得到以下结果:

MariaDB [world]> EXPLAIN SELECT * FROM (SELECT * FROM City WHERE Population > 1*1000) AS big_city WHERE big_city.Country='Germany';
+----+-------------+-------+------+--------------------+---------+---------+-------+------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+--------------------+---------+---------+-------+------+------------------------------------+
| 1 | SIMPLE | City | ref | Population,Country | Country | 3 | const | 90 | Using index condition; Using where |
+----+-------------+-------+------+--------------------+---------+---------+-------+------+------------------------------------+
1 row in set (0.00 sec)

从上面的结果可以看出:

  1. 只有一行输出,说明子查询已经被合并到上级的 SELECT 语句;
  2. 通过Country列访问City表,Country='Germany' 用来构建表上的 ref 访问;
  3. 查询将读取大约90行,这是对于之前的4079行读加上4068行临时表读/写的一个很大的改进。

Factsheet

派生表(FROM子句中的子查询)可以在没有 grouping, aggregates, or ORDER BY ...  LIMIT 子句时合并到他们的父查询中。这个优化默认开启,可通过如下关闭:

set @@optimizer_switch='derived_merge=OFF'

不支持该优化的Maria和MySQL版本将执行子查询,这可以导致一个著名的Bug(see e.g. MySQL Bug #44802),从MariaDB 5.3+和MySQL 5.6+ 开始,EXPLAIN命令立即执行,无论 derived_merge 如何设置。

Reference:

Derived Table Merge Optimization

MySQL 派生表(Derived Table) Merge Optimization的更多相关文章

  1. MySQL派生表(derived)优化一例

    1.什么是派生表derived 关键字:子查询–>在From后where前的子查询 mysql; +----+-------------+------------+------+-------- ...

  2. mysql错误:“ Every derived table must have its own alias”(每个派生出来的表都必须有一个自己的别名)

    自我感悟: 由此可以延伸,我们得到一个结果集,可以通过as XXX的方式,把结果集给当作一张表来用,以实现子查询: 一般在多表查询时,会出现此错误. 因为,进行嵌套查询的时候子查询出来的的结果是作为一 ...

  3. MySQL错误:Every derived table must have its own alias

    Every derived table must have its own alias 派生表都必须有自己的别名 一般在多表查询时,会出现此错误. 因为,进行嵌套查询的时候子查询出来的的结果是作为一个 ...

  4. mysql—mysql错误Every derived table must have its own alias解决

    Every derived table must have its own alias 这句话的意思是说每个派生出来的表都必须有一个自己的别名. 一般在多表查询时,会出现此错误. 因为,进行嵌套查询的 ...

  5. MySql 1248 - Every derived table must have its own alias

    执行一个sql语句,报错:1248 - Every derived table must have its own alias 提示说每一个衍生出来的表,必须要有自己的别名 执行子查询的时候,外层查询 ...

  6. 数据库~Mysql派生表注意的几点~关于百万数据的慢查询问题

    基础概念 派生表是从SELECT语句返回的虚拟表.派生表类似于临时表,但是在SELECT语句中使用派生表比临时表简单得多,因为它不需要创建临时表的步骤. 术语:*派生表*和子查询通常可互换使用.当SE ...

  7. mysql 创建表 create table详解

      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ...

  8. 修改MYSQL数据库表的字符集

    MySQL 乱码的根源是的 MySQL 字符集设置不当的问题,本文汇总了有关查看 MySQL 字符集的命令.包括查看 MySQL 数据库服务器字符集.查看 MySQL 数据库字符集,以及数据表和字段的 ...

  9. MYSQL优化派生表(子查询)在From语句中的

    Mysql 在5.6.3中,优化器更有效率地处理派生表(在from语句中的子查询): 优化器推迟物化子查询在from语句中的子查询,知道子查询的内容在查询正真执行需要时,才开始物化.这一举措提高了性能 ...

随机推荐

  1. 理解c/c++指针和引用

    1 指针的指针 比如int* a,那么a是指向一个int型的对象的.也就是说,*前面的类型是该指针指向的对象的类型. 同理int** a的话,a指向一个int*型的对象,也就是说,它指向的对象也是一个 ...

  2. 大数据之ES系列——第一篇 ElasticSearch2.2 集群安装部署

    第一部分  安装准备 准备三台主机节点: hc11.spads  192.168.160.181 hc12.spads  192.168.160.182 hc13.spads  192.168.160 ...

  3. ubuntu搭建mysql

    步骤1 – 安装MySQL 在 Ubuntu 16.04 中,默认情况下,只有最新版本的 MySQL 包含在 APT 软件包存储库中.在撰写本文时,那是 MySQL 5.7 要安装它,只需更新服务器上 ...

  4. complex brain network

    Organization, development and function of complex brain networks The Brain as a Complex System: Usin ...

  5. ModuleNotFoundError: No module named 'numpy.core._multiarray_umath' ImportError: numpy.core.multiarray failed to import

      出现以下错误:可能是因为你的numpy版本太低 更新numpy的版本 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgra ...

  6. ffmpeg: error while loading shared libraries: libavdevice.so.52

    今天在编译安装ffmpeg的时候出现了题目中的问题,最终解决方案如下: errors: ffmpeg正常安装后执行ffmpeg时出现如下错误:ffmpeg: error while loading s ...

  7. FusionCharts Free 甘特图

    用FusionCharts做甘特图 1.同步方式(用xml格式字符) 前台aspx代码 <!DOCTYPE html> <html xmlns="http://www.w3 ...

  8. jsp报An error has occurred. See error log for more details. Argument not valid错误

    An error has occurred. See error log for more details. Argument not valid 翻译过来是:一个错误已经发生.看到更多的细节错误日志 ...

  9. bzoj2132【圈地计划】

    题面 思路: 一开始以为和为了博多一样,两边连一样的,后来发现中间连负边的话根本不会割,即割断两块收益为负,所以WA的起飞…… 正解是先黑白染色,每个点和它周围的点连边方式不同.对于黑点A,S--&g ...

  10. 百度地图API简单应用——1.根据地址查询经纬度

    这几天比较空闲,就接触了下百度地图的API(开发者中心链接地址:http://developer.baidu.com),发现调用还是挺方便的.只要简单几步注册下,就可以获得一个Key,就能直接调用(P ...