关于java:SQL查询的底层运行原理分析

37次阅读

共计 3314 个字符,预计需要花费 9 分钟才能阅读完成。

SQL 语言无处不在。SQL 曾经不仅仅是技术人员的专属技能了,仿佛人人都会写 SQL,就如同人人都是产品经理一样。如果你是做后盾开发的,那么 CRUD 就是粗茶淡饭。如果你是做数仓开发的,那么写 SQL 可能占据了你的大部分工作工夫。咱们在了解 SELECT 语法的时候,还须要理解 SELECT 执行时的底层原理。只有这样,能力让咱们对 SQL 有更粗浅的意识。本文分享将逐渐合成 SQL 的执行过程,心愿对你有所帮忙。

数据筹备

本文旨在阐明 SQL 查问的执行过程,不会波及太简单的 SQL 操作,次要波及两张表:citizencity, 具体数据如下所示:

CREATE TABLE citizen (name CHAR ( 20), 
    city_id INT (10) 
);


CREATE TABLE city (city_id INT ( 10), 
    city_name CHAR (20) 
);

INSERT INTO city
VALUES
    (1, "上海"),
    (2, "北京"),
    (3, "杭州");
    
    
INSERT INTO citizen
VALUES
("tom",3),
("jack",2),
("robin",1),
("jasper",3),
("kevin",1),
("rachel",2),
("trump",3),
("lilei",1),
("hanmeiei",1);

查问执行程序

本文所波及的查问语句如下,次要是 citizen 表与 city 表进行 join,而后筛掉 city_name != “ 上海 ” 的数据,接着依照 city_name 进行分组,统计每个城市总人数大于 2 的城市,具体如下:

查问语句

SELECT 
    city.city_name AS "City",
    COUNT(*) AS "citizen_cnt"
FROM citizen
  JOIN city ON citizen.city_id = city.city_id 
WHERE city.city_name != '上海'
GROUP BY city.city_name
HAVING COUNT(*) >= 2
ORDER BY city.city_name ASC
LIMIT 2

执行步骤

下面 SQL 查问语句的书写书序是:

SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ...

然而执行程序并不是这样,具体的执行程序如下步骤所示:

  • 1. 获取数据 (From, Join)
  • 2. 过滤数据 (Where)
  • 3. 分组 (Group by)
  • 4. 分组过滤 (Having)
  • 5. 返回查问字段 (Select)
  • 6. 排序与分页 (Order by & Limit / Offset)

尖叫提醒:本文旨在阐明通用的 SQL 执行底层原理,对于其优化技术不做思考,比方谓词下推、投影下推等等。

执行的底层原理

其实下面所说的 SQL 执行程序就是所谓的底层原理,当咱们在执行 SELECT 语句时,每个步骤都会产生一张 虚构表(virtual table),在执行下一步骤时,会将该虚构表作为输出。指的留神的是,这些过程是对用户通明的。

你能够留神到,SELECT 是先从 FROM 这一步开始执行的。在这个阶段,如果是多张表进行 JOIN,还会经验上面的几个步骤:

获取数据 (From, Join)

  • 首先会通过 CROSS JOIN 求笛卡尔积,相当于失去虚构表 vt1-1;
  • 接着通过 ON 条件进行筛选,虚构表 vt1-1 作为输出,输入虚构表 vt1-2;
  • 增加内部行。咱们应用的是左连贯、右链接或者全连贯,就会波及到内部行,也就是在虚构表 vt1-2 的根底上减少内部行,失去虚构表 vt1-3

过滤数据 (Where)

通过下面的步骤,咱们失去了一张最终的虚构表 vt1,在此表之上作用 where 过滤,通过筛选条件过滤掉不满足条件的数据,从而失去虚构表 vt2。

分组 (Group by)

通过 where 过滤操作之后,失去 vt2。接下来进行 GROUP BY 操作,失去两头的虚构表 vt3。

分组过滤 (Having)

在虚构表 vt3 的根底之上,应用 having 过滤掉不满足条件的聚合数据,失去 vt4。

返回查问字段 (Select)

当咱们实现了条件筛选局部之后,就能够筛选表中提取的字段,也就是进入到 SELECT 和 DISTINCT 阶段。首先在 SELECT 阶段会提取指标字段,而后在 DISTINCT 阶段过滤掉反复的行,别离失去两头的虚构表 vt5-1 和 vt5-2。

排序与分页 (Order by & Limit / Offset)

当咱们提取了想要的字段数据之后,就能够依照指定的字段进行排序,也就是 ORDER BY 阶段,失去虚构表 vt6。最初在 vt6 的根底上,取出指定行的记录,也就是 LIMIT 阶段,失去最终的后果,对应的是虚构表 vt7

具体执行步骤剖析

Step 1: 获取数据 (From, Join)

FROM citizen
JOIN city 

该过程的第一步是执行 From 子句中的语句,而后执行 Join 子句。这些操作的后果是失去两个表的笛卡尔积。

name city_id city_id city_name
tom 3 1 上海
tom 3 2 北京
tom 3 3 杭州
jack 2 1 上海
jack 2 2 北京
jack 2 3 杭州
robin 1 1 上海
robin 1 2 北京
robin 1 3 杭州
jasper 3 1 上海
jasper 3 2 北京
jasper 3 3 杭州
kevin 1 1 上海
kevin 1 2 北京
kevin 1 3 杭州
rachel 2 1 上海
rachel 2 2 北京
rachel 2 3 杭州
trump 3 1 上海
trump 3 2 北京
trump 3 3 杭州
lilei 1 1 上海
lilei 1 2 北京
lilei 1 3 杭州
hanmeiei 1 1 上海
hanmeiei 1 2 北京
hanmeiei 1 3 杭州

在 FROM 和 JOIN 执行完结之后,会依照 JOIN 的 ON 条件,筛选所须要的行

ON citizen.city_id = city.city_id
name city_id city_id city_name
tom 3 3 杭州
jack 2 2 北京
robin 1 1 上海
jasper 3 3 杭州
kevin 1 1 上海
rachel 2 2 北京
trump 3 3 杭州
lilei 1 1 上海
hanmeiei 1 1 上海

Step 2: 过滤数据 (Where)

取得满足条件的行后,将传递给 Where 子句。这将应用条件表达式评估每一行。如果行的计算结果不为 true,则会将其从汇合中删除。

WHERE city.city_name != '上海'
name city_id city_id city_name
tom 3 3 杭州
jack 2 2 北京
jasper 3 3 杭州
rachel 2 2 北京
trump 3 3 杭州

Step 3: 分组 (Group by)

下一步是执行 Group by 子句,它将具备雷同值的行分为一组。尔后,将按组对所有 Select 表达式进行评估,而不是按行进行评估。

GROUP BY city.city_name
GROUP_CONCAT(citizen.name) city_id city_name
jack,rachel 2 北京
tom,jasper,trump 3 杭州

Step 4: 分组过滤 (Having)

对分组后的数据应用 Having 子句所蕴含的谓词进行过滤

HAVING COUNT(*) >= 2

Step 5: 返回查问字段 (Select)

在此步骤中,处理器将评估查问后果将要打印的内容,以及是否有一些函数要对数据运行,例如 Distinct,Max,Sqrt,Date,Lower 等等。本案例中,SELECT 子句只会打印城市名称和其对应分组的 count(*)值,并应用标识符“City”作为 city_name 列的别名。

SELECT 
    city.city_name AS "City",
    COUNT(*) AS "citizen_cnt"
city citizen_cnt
北京 2
杭州 3

Step 6: 排序与分页 (Order by & Limit / Offset)

查问的最初解决步骤波及后果集的排序与输入大小。在咱们的示例中,依照字母程序升序排列,并输入两条数据后果。

ORDER BY city.city_name ASC
LIMIT 2
city citizen_cnt
北京 2
杭州 3

总结

本文次要分析了 SQL 语句的执行程序和底层原理,根本的 SQL 查问会分为六大步骤。本文联合具体事例,给出了每一步骤的具体后果,这样会对其执行的底层原理有更加粗浅的意识。

公众号『大数据技术与数仓』,回复『材料』支付大数据资料包

正文完
 0