目录

  • `sql` 语句的解析顺序
    • 测试数据
    • 想要的结果
    • `sql` 解析顺序
      • `FROM`
        • 笛卡尔积
      • `ON` 过滤
      • 添加外部列
      • `WHERE`
      • `GROUP BY`
      • `HAVING`
      • `SELECT`
      • `ORDER BY`
      • `LIMIT`

sql 语句的解析顺序

接下来再走一步,让我们看看一条 sql 语句的前世今生。首先看一下示例语句

SELECT DISTINCT< select_list >
FROM< left_table > < join_type >
JOIN < right_table > ON < join_condition >
WHERE< where_condition >
GROUP BY< group_by_list >
HAVING< having_condition >
ORDER BY< order_by_condition >
LIMIT < limit_number >

然而它的执行顺序是这样的

FROM <left_table>
ON <join_condition><join_type>
JOIN <right_table>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
SELECT
DISTINCT <select_list>
ORDER BY <order_by_condition>
LIMIT <limit_number>

测试数据

CREATE TABLE table1(uid VARCHAR(10) NOT NULL,name VARCHAR(10) NOT NULL,PRIMARY KEY(uid)
)ENGINE=INNODB DEFAULT CHARSET=UTF8;INSERT INTO table1(uid,name) VALUES('aaa','mike'),('bbb','jack'),('ccc','mike'),('ddd','mike');CREATE TABLE table2(oid INT NOT NULL auto_increment,uid VARCHAR(10),PRIMARY KEY(oid)
)ENGINE=INNODB DEFAULT CHARSET=UTF8;INSERT INTO table2(uid) VALUES('aaa'),('aaa'),('bbb'),('bbb'),('bbb'),('ccc'),(NULL);

想要的结果

SELECTa.uid,count( b.oid ) AS total
FROMtable1 AS aLEFT JOIN table2 AS b ON a.uid = b.uid
WHEREa.NAME = 'mike'
GROUP BYa.uid
HAVINGcount( b.oid ) < 2
ORDER BYtotal DESC LIMIT 1;

sql 解析顺序

FROM

当涉及多个表的时候,左边表的输出会作为右边表的输入,之后会生成一个虚拟表 VT1

笛卡尔积

计算两个相关联表的笛卡尔积 (CROSS JOIN) ,生成虚拟表 VT1-J1

mysql> select * from table1,table2;
+-----+------+-----+------+
| uid | name | oid | uid  |
+-----+------+-----+------+
| aaa | mike |   1 | aaa  |
| bbb | jack |   1 | aaa  |
| ccc | mike |   1 | aaa  |
| ddd | mike |   1 | aaa  |
| aaa | mike |   2 | aaa  |
| bbb | jack |   2 | aaa  |
| ccc | mike |   2 | aaa  |
| ddd | mike |   2 | aaa  |
| aaa | mike |   3 | bbb  |
| bbb | jack |   3 | bbb  |
| ccc | mike |   3 | bbb  |
| ddd | mike |   3 | bbb  |
| aaa | mike |   4 | bbb  |
| bbb | jack |   4 | bbb  |
| ccc | mike |   4 | bbb  |
| ddd | mike |   4 | bbb  |
| aaa | mike |   5 | bbb  |
| bbb | jack |   5 | bbb  |
| ccc | mike |   5 | bbb  |
| ddd | mike |   5 | bbb  |
| aaa | mike |   6 | ccc  |
| bbb | jack |   6 | ccc  |
| ccc | mike |   6 | ccc  |
| ddd | mike |   6 | ccc  |
| aaa | mike |   7 | NULL |
| bbb | jack |   7 | NULL |
| ccc | mike |   7 | NULL |
| ddd | mike |   7 | NULL |
+-----+------+-----+------+
28 rows in set (0.00 sec)

ON 过滤

基于虚拟表 VT1-J1 这一个虚拟表进行过滤,过滤出所有满足 ON 谓词条件的列,生成虚拟表 VT1-J2

注意:这里因为语法限制,使用了 WHERE 代替,从中读者也可以感受到两者之间微妙的关系

mysql> SELECT-> *-> FROM-> table1,-> table2-> WHERE-> table1.uid = table2.uid-> ;
+-----+------+-----+------+
| uid | name | oid | uid  |
+-----+------+-----+------+
| aaa | mike |   1 | aaa  |
| aaa | mike |   2 | aaa  |
| bbb | jack |   3 | bbb  |
| bbb | jack |   4 | bbb  |
| bbb | jack |   5 | bbb  |
| ccc | mike |   6 | ccc  |
+-----+------+-----+------+
6 rows in set (0.00 sec)

添加外部列

如果使用了外连接(LEFT,RIGHT,FULL),主表(保留表)中的不符合 ON 条件的列也会被加入到 VT1-J2 中,作为外部行,生成虚拟表 VT1-J3

mysql> SELECT-> *-> FROM-> table1 AS a-> LEFT OUTER JOIN table2 AS b ON a.uid = b.uid;
+-----+------+------+------+
| uid | name | oid  | uid  |
+-----+------+------+------+
| aaa | mike |    1 | aaa  |
| aaa | mike |    2 | aaa  |
| bbb | jack |    3 | bbb  |
| bbb | jack |    4 | bbb  |
| bbb | jack |    5 | bbb  |
| ccc | mike |    6 | ccc  |
| ddd | mike | NULL | NULL |
+-----+------+------+------+
7 rows in set (0.00 sec)

WHERE

VT1 过程中生成的临时表进行过滤,满足 WHERE 子句的列被插入到 VT2 表中

ON 的区别

  • 如果有外部列,ON 针对过滤的是关联表,主表(保留表)会返回所有的列
  • 如果没有添加外部列,两者的效果是一样的

应用:

  • 对主表的过滤应该放在 WHERE
  • 对于关联表,先条件查询后连接则用 ON,先连接后条件查询则用 WHERE
mysql> SELECT-> *-> FROM-> table1 AS a-> LEFT OUTER JOIN table2 AS b ON a.uid = b.uid-> WHERE-> a. NAME = 'mike';
+-----+------+------+------+
| uid | name | oid  | uid  |
+-----+------+------+------+
| aaa | mike |    1 | aaa  |
| aaa | mike |    2 | aaa  |
| ccc | mike |    6 | ccc  |
| ddd | mike | NULL | NULL |
+-----+------+------+------+
4 rows in set (0.00 sec)

GROUP BY

这个子句会把 VT2 中生成的表按照 GROUP BY 中的列进行分组。生成 VT3

GROUP BY 改变了对表的引用,将其转换为新的引用方式,能够对其进行下一级逻辑操作的列会减少

根据分组字段,将具有相同分组字段的记录归并成一条记录,因为每一个分组只能返回一条记录,除非是被过滤掉了,而不在分组字段里面的字段可能会有多个值,多个值是无法放进一条记录的,所以必须通过聚合函数将这些具有多值的列转换成单值

mysql> SELECT-> *-> FROM-> table1 AS a-> LEFT OUTER JOIN table2 AS b ON a.uid = b.uid-> WHERE-> a. NAME = 'mike'-> GROUP BY-> a.uid;
+-----+------+------+------+
| uid | name | oid  | uid  |
+-----+------+------+------+
| aaa | mike |    1 | aaa  |
| ccc | mike |    6 | ccc  |
| ddd | mike | NULL | NULL |
+-----+------+------+------+
3 rows in set (0.00 sec)

HAVING

这个子句对 VT3 表中的不同的组进行过滤,只作用于分组后的数据,满足 HAVING 条件的子句被加入到 VT4 表中

mysql> SELECT-> *-> FROM-> table1 AS a-> LEFT OUTER JOIN table2 AS b ON a.uid = b.uid-> WHERE-> a. NAME = 'mike'-> GROUP BY-> a.uid-> HAVING-> count(b.oid) < 2;
+-----+------+------+------+
| uid | name | oid  | uid  |
+-----+------+------+------+
| ccc | mike |    6 | ccc  |
| ddd | mike | NULL | NULL |
+-----+------+------+------+
2 rows in set (0.00 sec)

SELECT

mysql> SELECT-> a.uid,-> count(b.oid) AS total-> FROM-> table1 AS a-> LEFT OUTER JOIN table2 AS b ON a.uid = b.uid-> WHERE-> a. NAME = 'mike'-> GROUP BY-> a.uid-> HAVING-> count(b.oid) < 2;
+-----+-------+
| uid | total |
+-----+-------+
| ccc |     1 |
| ddd |     0 |
+-----+-------+
2 rows in set (0.00 sec)

ORDER BY

mysql> SELECT-> a.uid,-> count(b.oid) AS total-> FROM-> table1 AS a-> LEFT OUTER JOIN table2 AS b ON a.uid = b.uid-> WHERE-> a. NAME = 'mike'-> GROUP BY-> a.uid-> HAVING-> count(b.oid) < 2-> ORDER BY-> total DESC;
+-----+-------+
| uid | total |
+-----+-------+
| ccc |     1 |
| ddd |     0 |
+-----+-------+
2 rows in set (0.00 sec)

LIMIT

当偏移量很大时效率是很低的,可以这么做:

  • 采用子查询的方式优化,在子查询里先从索引获取到最大 id,然后倒序排,再取 N 行结果集
  • 采用 INNER JOIN 优化,JOIN 子句里也优先从索引获取 ID 列表,然后直接关联查询获得最终结果
mysql> SELECT-> a.uid,-> count(b.oid) AS total-> FROM-> table1 AS a-> LEFT JOIN table2 AS b ON a.uid = b.uid-> WHERE-> a. NAME = 'mike'-> GROUP BY-> a.uid-> HAVING-> count(b.oid) < 2-> ORDER BY-> total DESC-> LIMIT 1;
+-----+-------+
| uid | total |
+-----+-------+
| ccc |     1 |
+-----+-------+
1 row in set (0.00 sec)

至此 sql 的解析之旅就结束了,上图总结一下

mysql的架构及查询sql的执行流程(二)相关推荐

  1. 在 MySQL 中使用 explain 查询 SQL 的执行计划(转自: 数据分析与开发)

    **来源:Oo若离oO my.oschina.net/ruoli/blog/1807394** 1.什么是MySQL执行计划 要对执行计划有个比较好的理解,需要先对MySQL的基础结构及查询基本原理有 ...

  2. 在MySQL中使用explain查询SQL的执行计划

    1.什么是MySQL执行计划 要对执行计划有个比较好的理解,需要先对MySQL的基础结构及查询基本原理有简单的了解. MySQL本身的功能架构分为三个部分,分别是 应用层.逻辑层.物理层,不只是MyS ...

  3. 面试官:说说一条查询sql的执行流程和底层原理?

    作者:孤独烟,资深后端工程师,业内知名原创作者 一条查询SQL执行流程图如下 本文改编自<高性能Mysql>,烟哥用小说的形式来讲这个内容. 序章 自我介绍 我是一条sql,就是一条长长的 ...

  4. 一文读懂查询sql的执行流程和底层原理

    前言 天天和数据库打交道,一天能写上几十条SQL语句,但你知道我们的系统是如何和数据库交互的吗?MySQL如何帮我们存储数据.又是如何帮我们管理事务?-是不是感觉真的除了写几个「select * fr ...

  5. openGauss简单查询SQL的执行流程解析

    目录 简单查询的执行 gdb调试 上一期酷哥分析了openGauss数据库的启动过程,包括主线程,辅助线程及业务处理线程的启动过程,这一期主要分析简单查询语句在业务处理线程Postgres上的执行流程 ...

  6. 01 | 基础架构:MySQL基本架构和查询语句的执行

    ⚠️:文章记叙的顺序和阅读顺序一致.

  7. 【mysql技术内幕1】mysql基础架构-一条SQL查询语句是如何执行的

    文章目录 1 一条SQL查询语句是如何执行的 2 mysql体系结构 3 InnoDB存储引擎 4 总结 1 一条SQL查询语句是如何执行的 ​ 通常我们使用数据库,都是将数据库看成一个整体,我们的应 ...

  8. mysql查看执行计划_MySql中如何使用 explain 查询 SQL 的执行计划

    explain命令是查看查询优化器如何决定执行查询的主要方法. 这个功能有局限性,并不总会说出真相,但它的输出是可以获取的最好信息,值得花时间去了解,因为可以学习到查询是如何执行的. 1.什么是MyS ...

  9. 详解MySQL的逻辑架构和SQL语句执行流程

    文章目录 1. 逻辑架构 1.1 连接层 1.2 服务层 1.3 引擎层 1.3.1 InnoDB 存储引擎 1.3.2 MyISAM 存储引擎 1.3.3 其他存储引擎 1.4 存储层 3. SQL ...

  10. explain如何查看mysql_MySql中如何使用 explain 查询 SQL 的执行计划

    explain命令是查看查询优化器如何决定执行查询的主要方法. 这个功能有局限性,并不总会说出真相,但它的输出是可以获取的最好信息,值得花时间去了解,因为可以学习到查询是如何执行的. 1.什么是MyS ...

最新文章

  1. 如何处理几十万条并发数据?
  2. 算法与数据结构--图的实现、基本操作及应用
  3. python太慢了-python 读取大文件越来越慢
  4. sqlite developer注册方法
  5. 2021互联网医疗行业洞察
  6. 微软官方大秀DX12:性能暴涨50%
  7. php利用mht导出word,解析掌握PHP导出Word文档原理
  8. 浅析 路印协议--Loopring 及整体分析 Relay 源码
  9. 个人对回调函数的理解(personal understanding of callback function)
  10. 系统分析师 VS 系统架构设计师,哪个证书含金量比较高?
  11. 基于JAVA的抽奖系统
  12. 英语六级常考核心词汇01
  13. scrapy settings和管道的深入
  14. iOS9获取手机序列号serialNumber(UDID)
  15. 史上最简单的spark教程第十三章-SparkSQL编程Java案例实践(终章)
  16. javascript 实现购物车多项物品累计求总价案例 ,价格保留两位小数
  17. C语言课程设计——宾馆管理系统
  18. Y z推荐菜东家 易订货生鲜系统_新零售·新生鲜——易订货生鲜专版客户交流会(贵阳站)圆满结束!...
  19. 入门 - 01- Java帝国的诞生
  20. C语言 学生管理系统 c++ 学生管理系统

热门文章

  1. ML for trading -cs7646-01
  2. 自动驾驶1-7: 进入自动驾驶汽车行业的建议Advice for Breaking into the Self-Driving Cars Industry
  3. 容器技术Docker K8s 30 容器服务ACK基础与进阶-弹性伸缩
  4. 翻译:Swift 5.1中的Protocol面向协议的编程教程:从入门到精通
  5. centos6配置mysql5.7_CentOS 6.7 下 MYSQL 5.7 的安装与配置
  6. k-means 及其改进 数库
  7. must be str,not int
  8. 面试题:100个白球,100个黑球,每次取两个
  9. 矩阵论7,8,9作业
  10. HashMap与ConcurrentHashMap的底层原理