mysql的架构及查询sql的执行流程(二)
目录
- `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的执行流程(二)相关推荐
- 在 MySQL 中使用 explain 查询 SQL 的执行计划(转自: 数据分析与开发)
**来源:Oo若离oO my.oschina.net/ruoli/blog/1807394** 1.什么是MySQL执行计划 要对执行计划有个比较好的理解,需要先对MySQL的基础结构及查询基本原理有 ...
- 在MySQL中使用explain查询SQL的执行计划
1.什么是MySQL执行计划 要对执行计划有个比较好的理解,需要先对MySQL的基础结构及查询基本原理有简单的了解. MySQL本身的功能架构分为三个部分,分别是 应用层.逻辑层.物理层,不只是MyS ...
- 面试官:说说一条查询sql的执行流程和底层原理?
作者:孤独烟,资深后端工程师,业内知名原创作者 一条查询SQL执行流程图如下 本文改编自<高性能Mysql>,烟哥用小说的形式来讲这个内容. 序章 自我介绍 我是一条sql,就是一条长长的 ...
- 一文读懂查询sql的执行流程和底层原理
前言 天天和数据库打交道,一天能写上几十条SQL语句,但你知道我们的系统是如何和数据库交互的吗?MySQL如何帮我们存储数据.又是如何帮我们管理事务?-是不是感觉真的除了写几个「select * fr ...
- openGauss简单查询SQL的执行流程解析
目录 简单查询的执行 gdb调试 上一期酷哥分析了openGauss数据库的启动过程,包括主线程,辅助线程及业务处理线程的启动过程,这一期主要分析简单查询语句在业务处理线程Postgres上的执行流程 ...
- 01 | 基础架构:MySQL基本架构和查询语句的执行
⚠️:文章记叙的顺序和阅读顺序一致.
- 【mysql技术内幕1】mysql基础架构-一条SQL查询语句是如何执行的
文章目录 1 一条SQL查询语句是如何执行的 2 mysql体系结构 3 InnoDB存储引擎 4 总结 1 一条SQL查询语句是如何执行的 通常我们使用数据库,都是将数据库看成一个整体,我们的应 ...
- mysql查看执行计划_MySql中如何使用 explain 查询 SQL 的执行计划
explain命令是查看查询优化器如何决定执行查询的主要方法. 这个功能有局限性,并不总会说出真相,但它的输出是可以获取的最好信息,值得花时间去了解,因为可以学习到查询是如何执行的. 1.什么是MyS ...
- 详解MySQL的逻辑架构和SQL语句执行流程
文章目录 1. 逻辑架构 1.1 连接层 1.2 服务层 1.3 引擎层 1.3.1 InnoDB 存储引擎 1.3.2 MyISAM 存储引擎 1.3.3 其他存储引擎 1.4 存储层 3. SQL ...
- explain如何查看mysql_MySql中如何使用 explain 查询 SQL 的执行计划
explain命令是查看查询优化器如何决定执行查询的主要方法. 这个功能有局限性,并不总会说出真相,但它的输出是可以获取的最好信息,值得花时间去了解,因为可以学习到查询是如何执行的. 1.什么是MyS ...
最新文章
- 如何处理几十万条并发数据?
- 算法与数据结构--图的实现、基本操作及应用
- python太慢了-python 读取大文件越来越慢
- sqlite developer注册方法
- 2021互联网医疗行业洞察
- 微软官方大秀DX12:性能暴涨50%
- php利用mht导出word,解析掌握PHP导出Word文档原理
- 浅析 路印协议--Loopring 及整体分析 Relay 源码
- 个人对回调函数的理解(personal understanding of callback function)
- 系统分析师 VS 系统架构设计师,哪个证书含金量比较高?
- 基于JAVA的抽奖系统
- 英语六级常考核心词汇01
- scrapy settings和管道的深入
- iOS9获取手机序列号serialNumber(UDID)
- 史上最简单的spark教程第十三章-SparkSQL编程Java案例实践(终章)
- javascript 实现购物车多项物品累计求总价案例 ,价格保留两位小数
- C语言课程设计——宾馆管理系统
- Y z推荐菜东家 易订货生鲜系统_新零售·新生鲜——易订货生鲜专版客户交流会(贵阳站)圆满结束!...
- 入门 - 01- Java帝国的诞生
- C语言 学生管理系统 c++ 学生管理系统
热门文章
- ML for trading -cs7646-01
- 自动驾驶1-7: 进入自动驾驶汽车行业的建议Advice for Breaking into the Self-Driving Cars Industry
- 容器技术Docker K8s 30 容器服务ACK基础与进阶-弹性伸缩
- 翻译:Swift 5.1中的Protocol面向协议的编程教程:从入门到精通
- centos6配置mysql5.7_CentOS 6.7 下 MYSQL 5.7 的安装与配置
- k-means 及其改进 数库
- must be str,not int
- 面试题:100个白球,100个黑球,每次取两个
- 矩阵论7,8,9作业
- HashMap与ConcurrentHashMap的底层原理