SQL 的执行顺序以及它的重要性与元数据
![SQL的执行顺序以及它的重要性与元数据](https://static001.geekbang.org/infoq/63/63e384be426c92d3fb2638e697d5b3c7.png)
本文是一个关于 SQL 与构建 SQL 血缘内容,属于作者原撮。其中 SQL 的图是来自 @Josep Ferrer。
两个知识点
SQL 的执行顺序与解释器
2.SQL 解析器构思元数据并产出影响与血缘分析
一、SQL 的执行顺序与解释器
先来看一条完整的 SQL
一个比较完整的 SQL 查询语句的编写顺序:
SELECT DISTINCT Table1., Table2.FROMTable1 JOIN Table2 ON matching_conditionWHERE constraint_expressionGROUP BY [columns]HAVING constraint_expressionORDER BY [columns]
LIMIT count 这条 SQL 的关键字:
![](https://static001.geekbang.org/infoq/44/44bef8065e52636362b12649f6797d04.png)
![](https://static001.geekbang.org/infoq/61/61e1fe2600825291c13751c863341d54.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
SQL 在实际执行时并不是完全按照使用者编写的顺序来的。了解执行顺序有助于使用者理解 SQL 的运行机制,写出更加高效的查询语句。
其具体的执行顺序
FROM Table1 和 JOIN Table2 把两个表连接起来。连接的条件是 ON Table1.col1 = Table2.col2,即两个表的某些列相等时进行连接
执行 WHERE constraint_expression,根据约束表达式过滤不符合条件的行
接着是 GROUP BY [columns],按照指定的列将结果集分组
再执行 HAVING constraint_expression,对分组后的结果集进一步过滤
之后执行 SELECT,选择结果集需要保留的列
再执行 ORDER BY [columns],按指定的列对结果集排序
最后通过 LIMIT count 限制结果集数量,返回前 count 行数据
![](https://static001.geekbang.org/infoq/f0/f05d5804940e4fb299f74ce4f0422b94.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
再来个例子:有两张用户表分别是
![](https://static001.geekbang.org/infoq/54/54861b0d861ad570dd4d47b83be64ff8.png)
要执行的 SQL 如下:
SELECTu.region,SUM(o.amount) AS total_amountFROM users uJOIN orders oON u.user_id = o.user_idWHERE o.create_time BETWEEN '2023-01-01' AND '2023-12-31'GROUP BY u.regionHAVING SUM(o.amount) > 1000000ORDER BY total_amount DESCLIMIT 10;
按照的顺序:
FROM & JOIN: 首先从用户表(users)和订单表(orders)中读取数据。通过 JOIN 将两张表按照用户 ID(user_id)进行关联,得到一个中间结果集。中间结果集包含了用户的地区信息和订单的金额、时间等信息。
WHERE: 对上一步得到的中间结果集进行过滤。条件是订单的创建时间(create_time)在'2023-01-01'到'2023-12-31'之间。这一步删除了不在指定时间范围内的订单数据。
GROUP BY: 将上一步的结果集按照用户所在地区(region)进行分组。这一步将相同地区的用户订单信息聚合在一起。
HAVING: 对分组后的结果集进一步过滤。条件是每个地区的总订单金额大于 1000000。这一步删除了消费总额不满足条件的地区。
SELECT: 选择结果集中需要保留的列,包括地区(region)和总金额(total_amount)。其中总金额是通过 SUM(o.amount)计算得到的。
ORDER BY: 按照总金额(total_amount)对结果集进行倒序排序。这一步将消费总额高的地区排在前面。
LIMIT: 限制结果集的数量为 10。这一步返回消费总额最高的前 10 个地区。
最终得到了一个按照消费总额倒序排列的地区列表,可以清楚地看到哪些地区的用户消费最多。通过这个例子,我们综合运用了 SQL 的执行顺序和 JOIN 操作,实现了一个实际的数据分析需求。
二.SQL 解析器构思元数据并产出影响与血缘分析
下图是笔者在 2009 年与技术一起做元数据产品时核心部分之一 SQL 解释器
![](https://static001.geekbang.org/infoq/01/018a37d1a8b4899ca6a4715223687021.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
通过该解释器将 ETL 的 SQL 全部解析
ETL 名称:in 、out、表、字段、条件 的结构。最后将这些结构连起来就是一个血缘图。下图是完整 SQL 元数据结构部分模型
![](https://static001.geekbang.org/infoq/0d/0d1547cb0af0430022a1b1095b574800.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
其主要的内容可以简单理解为,将 SQL 语句解析为语法分析树,然后通过 Toke 序列转化为语法分析树,最终抽象语法树被传递给错误检查和语义分析阶段进行处理。
SQL 语句:用户或应用程序提交一个或多个 SQL 语句给数据库执行。
SQL 语句解析:数据库接收到 SQL 语句后,会对其进行词法和语法分析。词法分析将 SQL 语句分解成一个个 Token(如关键字、标识符、运算符等),语法分析则根据 SQL 语法规则验证这些 Token 序列是否构成一个有效的 SQL 语句
生成语法树:如果 SQL 语句通过了词法和语法检查,解析器会根据语句的结构生成一棵语法树。语法树以树形结构表示 SQL 语句各个语法单元之间的关系,叶子节点对应 SQL 语句中的原子元素如表名、列名、值等,非叶节点则对应各种 SQL 子句如 SELECT、FROM、WHERE 等
语义分析:语法树生成后还需进行语义检查,如检查表和列是否存在,列之间的数据类型是否匹配等
版权声明: 本文为 InfoQ 作者【松子(李博源)】的原创文章。
原文链接:【http://xie.infoq.cn/article/0d2b15b256df2ddfb35661651】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论