SQL查询语句的执行流程(以Oracle举例)
首先, 准备两张表
用户表user
角色表role
先来一个基本的查询语句
SELECT * FROM "user" u, "role" r WHERE u."rid"=r."rid" ORDER BY u."age" DESC
这时发生了什么呢
一共三个步骤
- 加载表
- 筛选数据
- 返回数据
那么按照这个流程, 解析一下上面的SQL语句的运行流程
- 匹配到SELECT关键字, 是查询语句, 寻找form
- 匹配到FROM关键字, 找到其后面的"user" u, “role” r 加载表到内存中
- 将FROM后面的所有表做笛卡尔积, 生成虚表VT1, 此时加载表执行完毕
- 匹配WHERE关键字, 执行 u.“rid” = r.“rid” 进行表的筛选, 生成虚表VT2
- 此时得到的VT2大致满足了我们的要求, 但还差一步, 数据处理
- 执行 ORDER BY u.“age” DESC 将VT2的数据进行排序, 生成VT3
- 返回VT3
此时, 我们就能拿到SQL语句预期拿到的数据了
这就是本条SQL产生的三条虚拟表的样子
==================== 华丽的分割线 ====================
如果上面的内容你能理解的话, 那么我们来详细谈谈 SQL三联
- 加载表
加载表是将一条查询语句中所需要的表加载进内存, 并按照连接方式生成虚拟表VT1
加载进内存很好理解, 就是把所有需要的表找到, 从磁盘加载进内存
但是可能有的同学想到了, 子查询中可以将查询语句的结果当做一张表给外部使用, 所以加载表也是可以加载其他SQL生成的虚拟表的
生成虚拟表, 这个有些难, 首先表之间要先进行表连接(隐式内连接, 内连接, 左联接, 右连接)
表连接要先做笛卡尔积(生成所有的可能), 在通过连接条件进行筛选, 过滤掉大部分无用数据, 生成虚拟表VT1
- 筛选数据
去掉不满足条件的, 留下符合的
这步是将加载表生成的VT1通过各种条件(例: u.“username” = ‘张三’) 进行筛选, 不满足条件的将被去除, 然后生成虚拟表VT2
处了用where进行筛选, 还可以用GROUP BY进行分组, 和使用HAVING进行分组筛选
分组后一张完整的虚拟表VT2将被按照分组字段分成n个小虚拟表, 这些小虚拟表组成一个虚拟表数组
然后进行分组筛选, 这会遍历虚拟表数组中的所有虚拟表进行筛选, 所以十分浪费资源, 同样的, 不满足条件的将被去除
- 返回数据
数据将变成你想要的模样
从筛选数据生成的虚拟表后虚拟表数组提取你想要的数据, 这并不会去除那些不符合要求的数据
这里有一个要求, 就是处理完成的数据一定要是一张完整的虚拟表, 不能是虚拟表数组,
这也就是为什么分组之后只能返回分组字段(因为其他字段可能有多条数据),
当然 ,也可以返回聚合函数(聚合函数将多条数据聚合成为一条)
在返回数据之前, 还可以使用排序或分页进行最后的数据处理, 然后按照返回的格式, 生成你想要的数据(比如只要名字和年龄), 无论如何, 最后返回的都只能是一张完整的虚表, 这张虚拟表还可以被其他SQL当做表加载使用, 也就是子查询
==================== 华丽的分割线 ====================
到这里SQL查询语句的执行流程就差不多了, 如果完全理解了这里, 你便能灵活使用SQL语句查询出想要的数据, 而不再拘泥于格式
但是Oracle还有函数处理及集合运算, 这部分有事怎么回事呢
敬请期待…