小白学习MySQL - Derived Table

Posted bisal(Chen Liu)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小白学习MySQL - Derived Table相关的知识,希望对你有一定的参考价值。

最近一位朋友提了这个问题,mysql中一条SQL执行计划,如下所示,其中有PRIMARY、<derived2>、DERIVED这些内容,他怎么和SQL对应上?

MySQL确实有些和Oracle不同的专业术语,但是背后的原理机制是相通的。

为了说明,模拟创建测试表,

create table t01(
  id int,
  code varchar(10),
  start_date datetime,
  title varchar(10),
  content varchar(30),
  class int,
  end_date datetime
);

插入一些数据,

bisal@mysqldb:  [test]> select * from t01;
+------+--------+---------------------+---------+------------+-------+---------------------+
| id   | code   | start_date          | title   | content    | class | end_date            |
+------+--------+---------------------+---------+------------+-------+---------------------+
|    1 | code1  | 2022-01-01 00:00:00 | title1  | content_1  |     1 | 2022-01-03 00:00:00 |
|    2 | code2  | 2022-01-02 00:00:00 | title2  | content_2  |     3 | 2022-01-03 00:00:00 |
|    3 | code3  | 2022-01-03 00:00:00 | title3  | content_3  |     2 | 2022-01-03 00:00:00 |
|    4 | code4  | 2022-01-04 00:00:00 | title4  | content_4  |     1 | 2022-01-06 00:00:00 |
|    5 | code5  | 2022-01-05 00:00:00 | title5  | content_5  |     1 | 2022-01-07 00:00:00 |
|    6 | code6  | 2022-01-06 00:00:00 | title6  | content_6  |     2 | 2022-01-10 00:00:00 |
|    7 | code7  | 2022-01-07 00:00:00 | title7  | content_7  |     1 | 2022-01-11 00:00:00 |
|    8 | code8  | 2022-01-08 00:00:00 | title8  | content_8  |     1 | 2022-01-12 00:00:00 |
|    9 | code9  | 2022-01-09 00:00:00 | title9  | content_9  |     3 | 2022-01-10 00:00:00 |
|   10 | code10 | 2022-01-10 00:00:00 | title10 | content_10 |     1 | 2022-01-13 00:00:00 |
+------+--------+---------------------+---------+------------+-------+---------------------+
10 rows in set (0.00 sec)

执行的是这条SQL,

bisal@mysqldb:  [test]>
    -> select * from (
    -> (select id, code, start_date, title, content, concat('测试1:', start_date), class, end_date
    -> from t01 t
    -> where id=1 and code='code1' and title='title1' and start_date>='2022-01-01' and start_date<='2022-01-05'
    -> order by end_date desc limit 1)
    -> union all
    -> (select id, code, start_date, title, content, concat('测试2:', start_date), class, end_date
    -> from t01 t
    -> where id=2 and code='code2' and title='title2' and start_date>='2022-01-01' and start_date<='2022-01-05'
    -> order by end_date desc limit 1)
    -> union all
    -> (select id, code, start_date, title, content, concat('测试3:', start_date), class, end_date
    -> from t01 t
    -> where id=3 and code='code3' and title='title3' and start_date>='2022-01-01' and start_date<='2022-01-05'
    -> order by end_date desc limit 1)
    -> union all
    -> (select id, code, start_date, title, content, concat('测试4:', title), class, end_date
    -> from t01 t
    -> where id=4 and code='code4' and title='title4' and start_date>='2022-01-01' and start_date<='2022-01-05' and end_date<='2022-01-05')
    -> union all
    -> (select id, code, start_date, title, content, concat('测试5:', content), class, end_date
    -> from t01 t
    -> where id=5 and code='code5' and title='title5' and start_date>='2022-01-01' and start_date<='2022-01-05'and end_date<='2022-01-05')
    -> ) tt order by class, end_date desc;

他的执行计划,就和文章开始提到的基本一致,

从官方文档中,我们可以了解到,什么是Derived Tables?简单来讲,就是会将FROM子句中出现的检索结果集当做一张表,例如FROM中的SELECT子查询就是一张derived table,而且每张FROM子句中的表都需要一个表别名,任何来自derived table的列必须有唯一的名称,其他要求和示例,可以参考链接,

https://dev.mysql.com/doc/refman/5.7/en/derived-tables.html

A derived table is an expression that generates a table within the scope of a query FROM clause. For example, a subquery in a SELECT statement FROM clause is a derived table:
SELECT … FROM (subquery) [AS] tbl_name 

The [AS] tbl_name clause is mandatory because every table in a FROM clause must have a name. Any columns in the derived table must have unique names

执行计划中的第一行<derived2>这张"表"是全表扫描,

原因就是上述SQL,实际可以理解为,对derived  table的检索,实际上是没有任何检索条件的,

select * from ( ... ) tt order by class, end_date desc;

其实仔细观察上面这个SQL,derived table中union all连接的前三个SQL检索条件基本是一致的,而union all连接的后两个SQL检索条件基本是一致的,只是SELECT中concat内容不同,因此能做改写。

以前三个SQL为例,concat通过case when判断不同的id和title条件下,应该输出的内容,where条件中带上之前所有的字段,改造完这就是独立的一条SQL,不存在子查询,

bisal@mysqldb:  [test]> explain
    -> select id, code, start_date, content,
    ->        (case when id=1 and code='code1' and title='title1' then concat('测试1:', start_date)
    ->              when id=2 and code='code2' and title='title2' then concat('测试2:', start_date)
    ->              when id=3 and code='code3' and title='title3' then concat('测试3:', start_date) end) c,
    ->        class, end_date
    -> from t01
    -> where id in (1, 2, 3) and title in ('title1', 'title2', 'title3')
    -> and start_date>='2022-01-01' and start_date<='2022-01-05'
    -> order by class, end_date desc;
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key        | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | t01   | NULL       | range | idx_t01_01    | idx_t01_01 | 5       | NULL |    3 |    10.00 | Using index condition; Using where; Using filesort |
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+----------------------------------------------------+
1 row in set, 1 warning (0.00 sec)

优化法则之一,就是少做事儿。如果改写成这个,最大的优势,就是同一张表只需要读取一次,而之前derived table中每个union all的子查询都需要读取一次表t01。

小白学习MySQL

小白学习MySQL - Generated Columns功能

小白学习MySQL - 增量统计SQL的需求 - 开窗函数的方案

小白学习MySQL - 统计的"投机取巧"

小白学习MySQL - 增量统计SQL的需求

小白学习MySQL - 你碰到过这种无法登陆的场景?

小白学习MySQL - 不同版本创建用户的些许区别

小白学习MySQL - 随机插入测试数据的工具

小白学习MySQL - varchar类型字段为什么经常定义成255?

小白学习MySQL - 变通创建索引的案例一则

小白学习MySQL - “投机取巧”统计表的记录数

小白学习MySQL - 一次慢SQL的定位

小白学习MySQL - TIMESTAMP类型字段非空和默认值属性的影响

小白学习MySQL - 聊聊数据备份的重要性

小白学习MySQL - InnoDB支持optimize table?

小白学习MySQL - table_open_cache的作用

小白学习MySQL - 表空间碎片整理方法

小白学习MySQL - 大小写敏感问题解惑

小白学习MySQL - only_full_group_by的校验规则

小白学习MySQL - max_allowed_packet

小白学习MySQL - mysqldump保证数据一致性的参数差异

小白学习MySQL - 查询会锁表?

小白学习MySQL - 索引键长度限制的问题

小白学习MySQL - MySQL会不会受到“高水位”的影响?

小白学习MySQL - 数据库软件和初始化安装

小白学习MySQL - 闲聊聊

如果您认为这篇文章有些帮助,还请不吝点下文章末尾的"点赞"和"在看",或者直接转发pyq,

近期更新的文章:

麒麟OS和龙芯环境编译安装GreatSQL

上小学之前要学会的本领指引

北京全天候核酸检测场所

足球队巡礼 - 英超西汉姆联

小白学习MySQL - Generated Columns功能

近期的热文:

"红警"游戏开源代码带给我们的震撼

文章分类和索引:

公众号1000篇文章分类和索引

以上是关于小白学习MySQL - Derived Table的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 派生表(Derived Table) Merge Optimization

mysql语法错误:Every derived table must have its own alias

小白学习MySQL - InnoDB支持optimize table?

mysql union出错: "Every derived table must have its own alias"

在使用MYSQL进行嵌套查询时出现:Every derived table must have its own alias错误解决方法

小白学习MySQL - table_open_cache的作用