MySQL 派生表(Derived Table) Merge Optimization
本文将通过演示告诉你: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个步骤:
- 执行子查询:(SELECT * FROM city WHERE population > 1*1000),正如查询语句中的那样;
- 把子查询的结果写到临时表 big_city ;
- 回读,应用上层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)
从上面的结果可以看出:
- 只有一行输出,说明子查询已经被合并到上级的 SELECT 语句;
- 通过Country列访问City表,Country='Germany' 用来构建表上的 ref 访问;
- 查询将读取大约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的更多相关文章
- MySQL派生表(derived)优化一例
1.什么是派生表derived 关键字:子查询–>在From后where前的子查询 mysql; +----+-------------+------------+------+-------- ...
- mysql错误:“ Every derived table must have its own alias”(每个派生出来的表都必须有一个自己的别名)
自我感悟: 由此可以延伸,我们得到一个结果集,可以通过as XXX的方式,把结果集给当作一张表来用,以实现子查询: 一般在多表查询时,会出现此错误. 因为,进行嵌套查询的时候子查询出来的的结果是作为一 ...
- MySQL错误:Every derived table must have its own alias
Every derived table must have its own alias 派生表都必须有自己的别名 一般在多表查询时,会出现此错误. 因为,进行嵌套查询的时候子查询出来的的结果是作为一个 ...
- mysql—mysql错误Every derived table must have its own alias解决
Every derived table must have its own alias 这句话的意思是说每个派生出来的表都必须有一个自己的别名. 一般在多表查询时,会出现此错误. 因为,进行嵌套查询的 ...
- MySql 1248 - Every derived table must have its own alias
执行一个sql语句,报错:1248 - Every derived table must have its own alias 提示说每一个衍生出来的表,必须要有自己的别名 执行子查询的时候,外层查询 ...
- 数据库~Mysql派生表注意的几点~关于百万数据的慢查询问题
基础概念 派生表是从SELECT语句返回的虚拟表.派生表类似于临时表,但是在SELECT语句中使用派生表比临时表简单得多,因为它不需要创建临时表的步骤. 术语:*派生表*和子查询通常可互换使用.当SE ...
- 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 ...
- 修改MYSQL数据库表的字符集
MySQL 乱码的根源是的 MySQL 字符集设置不当的问题,本文汇总了有关查看 MySQL 字符集的命令.包括查看 MySQL 数据库服务器字符集.查看 MySQL 数据库字符集,以及数据表和字段的 ...
- MYSQL优化派生表(子查询)在From语句中的
Mysql 在5.6.3中,优化器更有效率地处理派生表(在from语句中的子查询): 优化器推迟物化子查询在from语句中的子查询,知道子查询的内容在查询正真执行需要时,才开始物化.这一举措提高了性能 ...
随机推荐
- 【BZOJ4811】[Ynoi2017]由乃的OJ 树链剖分+线段树
[BZOJ4811][Ynoi2017]由乃的OJ Description 由乃正在做她的OJ.现在她在处理OJ上的用户排名问题.OJ上注册了n个用户,编号为1-",一开始他们按照编号排名. ...
- EasyRTMP实现对接海康、大华等IPCamera SDK进行RTMP推送直播功能
本文转自EasyDarwin团队Kim的博客:http://blog.csdn.net/jinlong0603 Demo项目介绍 EasyRTMP Demo代码下载地址https://github.c ...
- 为自己编写的windows应用程序制作安装包
1 写好了一个windows程序之后如何制作安装包 这个在vs中就可以直接发布了,可以制作msi的安装包和exe的安装包. 2 window应用程序安装包做了哪些事情 rpm安装包的话,只是把相应的文 ...
- CentOS-7-64bit 下为firefox安装flashplayer
最近更新了Centos 7 还是有一些不习惯的 给ff安flashplayer插件时,按centos 6.x的方法时都无法成功,后来find了一下,才知道firefox还有一个64bit的文件夹: 解 ...
- HDU 1829/POJ 2492 A Bug's Life
A Bug's Life Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tot ...
- jquery回顾part1——选择器
jQuery 选择器 选择器 实例 选取 * $("*") 所有元素 #id $("#lastname") id="lastname" 的元 ...
- centos服务器安装配置Postgre9.6
安装: STEP1:下载对应rpm yum install https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-6-x86_64 ...
- 最新版ADT(Build: v22.6.2)总是引用appcompat_v7的问题
昨天在ADT Manager里更新了一些组件,结果ADT不支持.索性直接下载了最新的ADT.但是发现无论创建什么类型的应用(无论支持的最低API是多少,或者是不是用模板),都会在创建应用的同时创建一个 ...
- 工艺(SAM)
传送门 用SAM可以非常轻松的解决问题. 只要把原串向SAM中插入两次,之后直接从\(t_0\)状态开始每次贪心跑最小就可以了. 因为这个题要用map,所以之前取begin即可. // luogu-j ...
- kafka数据可靠性深度解读【转】
1 概述 Kakfa起初是由LinkedIn公司开发的一个分布式的消息系统,后成为Apache的一部分,它使用Scala编写,以可水平扩展和高吞吐率而被广泛使用.目前越来越多的开源分布式处理系统如Cl ...