Apache Spark SQL 语法全景指南:从 DDL/DML 到数据检索、SQL 脚本与辅助语句
【免费下载链接】sparkApache Spark - A unified analytics engine for large-scale data processing项目地址: https://gitcode.com/gh_mirrors/sp/spark
Apache Spark SQL 是 Spark 生态中处理结构化数据的核心模块,而 SQL 语法是其对外提供的最直接、最广泛使用的接口。本文以 Spark 官方文档中 SQL Syntax 总览 为主体骨架,系统梳理 Spark SQL 支持的五类语句——DDL(数据定义)、DML(数据操作)、数据检索(SELECT 与 EXPLAIN)、SQL 脚本(过程化逻辑)以及辅助语句,并结合仓库中的 ANTLR 语法文件与解析器源码,讲清每类语句的定位、语法要点与底层解析机制。读完本文,你将能快速定位任意一条 Spark SQL 语句的完整语法定义,理解 Spark 如何将一条 SQL 文本逐步解析为可执行的逻辑计划与物理计划,并据此编写规范、可高效执行的查询。
一、从 SQL 语法文档到执行计划:Spark 的解析链路
在深入各类语句之前,先理解 Spark 如何处理一条 SQL。整个 SQL 语法体系由两大部分承载:
- 语法定义:仓库中 SqlBaseParser.g4 与 SqlBaseLexer.g4 是 ANTLR 4 文法文件(其声明"adapted from Presto's SqlBase.g4 grammar"),定义了从顶层
compoundOrSingleStatement到每个具体语句的完整语法规则。 - 解析实现:SparkSqlParser.scala 继承
AbstractSqlParser,通过parsePlanWithParameters调用语法文件的compoundOrSingleStatement()入口,将解析树交给SparkSqlAstBuilder转换为 Catalyst 的逻辑计划(LogicalPlan),若结果是CompoundPlanStatement(SQL 脚本复合体)则原样返回。
从语法文件可以看到解析器内置了若干可配置的行为开关,它们直接影响语句的解析语义:
| 语法文件成员开关 | 含义 | 关联配置 |
|---|---|---|
SQL_standard_keyword_behavior | 为 true 时关键字遵循 ANSI SQL 标准 | spark.sql.parser.ansi.enabled(配合 ANSI 模式) |
double_quoted_identifiers | 为 true 时双引号内容按标识符而非字符串解析 | spark.sql.parser.escapedStringLiterals相关 ANSI 设置 |
legacy_setops_precedence_enabled | 控制 INTERSECT 与 UNION/EXCEPT 的优先级(false 时遵循 SQL 标准) | spark.sql.legacy.setopsPrecedence.enabled |
legacy_identifier_clause_only | 控制IDENTIFIER('literal')的解析方式 | spark.sql.legacy.identifierClause |
single_character_pipe_operator_enabled | 是否允许单字符|作为 SQL 管道运算符 | 管道语法开关 |
顶层语法规则compoundOrSingleStatement由singleStatement或singleCompoundStatement组成,后者即BEGIN (NOT ATOMIC)? compoundBody? END形式的 SQL 脚本复合语句。而singleStatement内部又分为dmlStatement、use、setCatalog、createTable、analyze、showTables、explain、cacheTable、loadData等数十条具体规则——这正是文档中五类语句在语法层面的映射。理解了这条"文本 → 词法 → 语法树 → 逻辑计划 → 物理计划"的链路,后续阅读各类语句时就能知其然也知其所以然。
二、DDL 语句:定义与修改数据库对象结构
Data Definition Statements 用于创建或修改数据库中数据库对象的结构。Spark SQL 支持以下 DDL 语句:
| 语句 | 文档位置 | 用途 |
|---|---|---|
| ALTER DATABASE | sql-ref-syntax-ddl-alter-database.md | 修改数据库属性、位置 |
| ALTER TABLE | sql-ref-syntax-ddl-alter-table.md | 修改表结构(增删列、改分区、改属性等) |
| ALTER VIEW | sql-ref-syntax-ddl-alter-view.md | 修改视图定义 |
| COMMENT ON | sql-ref-syntax-ddl-comment.md | 为表/列添加注释 |
| CREATE DATABASE | sql-ref-syntax-ddl-create-database.md | 创建数据库 |
| CREATE FUNCTION (External) | sql-ref-syntax-ddl-create-function.md | 注册外部(Hive UDF/UDTF/UDAF)函数 |
| CREATE FUNCTION (SQL) | sql-ref-syntax-ddl-create-sql-function.md | 创建 SQL 标量/表值函数 |
| CREATE TABLE | sql-ref-syntax-ddl-create-table.md | 定义表(入口页,含三种子形态) |
| CREATE VIEW | sql-ref-syntax-ddl-create-view.md | 创建视图 |
| DECLARE VARIABLE | sql-ref-syntax-ddl-declare-variable.md | 声明会话级变量 |
| DROP DATABASE | sql-ref-syntax-ddl-drop-database.md | 删除数据库 |
| DROP FUNCTION | sql-ref-syntax-ddl-drop-function.md | 删除函数 |
| DROP TABLE | sql-ref-syntax-ddl-drop-table.md | 删除表 |
| DROP TEMPORARY VARIABLE | sql-ref-syntax-ddl-drop-variable.md | 删除临时变量 |
| DROP VIEW | sql-ref-syntax-ddl-drop-view.md | 删除视图 |
| REPAIR TABLE | sql-ref-syntax-ddl-repair-table.md | 恢复/刷新表分区元数据 |
| TRUNCATE TABLE | sql-ref-syntax-ddl-truncate-table.md | 清空表数据 |
| USE DATABASE | sql-ref-syntax-ddl-usedb.md | 切换当前数据库 |
2.1 CREATE TABLE:三种建表形态
CREATE TABLE的入口文档将其划分为三种形态:
- CREATE TABLE USING DATA_SOURCE:使用 DataSource 数据源(如
USING PARQUET、USING CSV)建表,可配合PARTITIONED BY、LOCATION、TBLPROPERTIES、OPTIONS等子句。 - CREATE TABLE USING HIVE FORMAT:使用 Hive SerDe 格式建表(
STORED AS、ROW FORMAT等)。 - CREATE TABLE LIKE:以一张已有表为模板创建同构新表。
语法层面,SqlBaseParser.g4 中的createTableHeader (LEFT_PAREN tableElementList RIGHT_PAREN)? tableProvider? createTableClauses (AS? query)?规则完整刻画了建表语法,其中AS? query即CREATE TABLE ... AS SELECT(CTAS)能力。与CREATE TABLE并列的还有replaceTableHeader对应的CREATE OR REPLACE TABLE。
2.2 变量声明:DECLARE / DROP TEMPORARY VARIABLE
值得关注的是DECLARE VARIABLE与DROP TEMPORARY VARIABLE两条语句,它们服务于 Spark 3.4+ 引入的 SQL 变量体系(配合参数化查询与 SQL 脚本)。语法文件中的declareVariable规则支持带DEFAULT值的变量声明。变量可进一步与文档中的 SET VAR、EXECUTE IMMEDIATE 配套使用,构成会话内可编程的数据处理环境。
三、DML 语句:增、改、删数据
Data Manipulation Statements 用于添加、变更或删除数据。Spark SQL 支持以下 DML 语句:
| 语句 | 文档位置 | 用途 |
|---|---|---|
| INSERT TABLE | sql-ref-syntax-dml-insert-table.md | 向表插入或覆盖数据 |
| INSERT OVERWRITE DIRECTORY | sql-ref-syntax-dml-insert-overwrite-directory.md | 将查询结果写入外部目录 |
| MERGE INTO | sql-ref-syntax-dml-merge-into.md | 依据源数据对目标表执行插入/更新/删除 |
| LOAD | sql-ref-syntax-dml-load.md | 从文件路径加载数据到 Hive 表 |
3.1 INSERT 的完整语法形态
INSERT语句插入新行或覆盖表中已有数据,插入行可由值表达式指定,也可由查询结果产生。其语法如下:
INSERT [ WITH SCHEMA EVOLUTION ] [ INTO | OVERWRITE ] [ TABLE ] table_identifier [ partition_spec ] [ ( column_list ) | [BY NAME] ] { VALUES ( { value | NULL } [ , ... ] ) [ , ( ... ) ] | query } INSERT [ WITH SCHEMA EVOLUTION ] INTO [ TABLE ] table_identifier [ BY NAME ] REPLACE WHERE boolean_expression query关键参数解析:
- WITH SCHEMA EVOLUTION:允许本次 INSERT 依据源查询自动演进目标表 schema(新增列、拓宽数据类型),具体能力取决于底层 connector。
- partition_spec:
PARTITION ( partition_col_name = partition_col_val [ , ... ] ),支持类型化字面量(如date'2019-01-02')。 - column_list:按列名将源查询列重排以匹配表 schema,需注意所有列必须真实存在且不重复,列数须与 VALUES/查询输出严格一致。
- BY NAME:默认按位置匹配列与嵌套字段;
BY NAME改为按名称匹配,允许源与目标列顺序不同。 - query:可来源于 SELECT、Inline Table 或
FROM语句。
语法文件中对应的INSERT (OVERWRITE | INTO)? ...规则将INSERT INTO、INSERT OVERWRITE与INSERT OVERWRITE DIRECTORY(含LOCAL、STORED AS等变体)统一收纳。仓库中的使用示例与测试大量覆盖了INSERT INTO ... VALUES、INSERT OVERWRITE TABLE、INSERT OVERWRITE DIRECTORY三种形态,例如在分区表students中插入单行:
CREATE TABLE students (name VARCHAR(64), address VARCHAR(64)) USING PARQUET PARTITIONED BY (student_id INT); INSERT INTO students VALUES ('Amy Smith', '123 Park Ave, San Jose', 111111);3.2 MERGE INTO 与 LOAD
- MERGE INTO:以源表(可通过
USING子句指定,含AS OF时态表)驱动,对目标表执行WHEN MATCHED(UPDATE/DELETE)与WHEN NOT MATCHED(INSERT)分支操作,是湖仓场景 upsert 的标准手段。 - LOAD:将本地或远程文件系统中的数据加载进 Hive 表,支持
LOAD DATA [LOCAL] INPATH ... INTO TABLE语法。
四、数据检索语句:SELECT 及其子句体系
Spark 支持符合 ANSI SQL 标准的SELECT语句,用于从一个或多个表中检索结果集。SELECT及其关联语句是 Spark SQL 使用频率最高、语法最丰富的部分,完整定义见 SELECT。
4.1 SELECT 整体语法
[ WITH with_query [ , ... ] ] select_statement [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select_statement, ... ] [ ORDER BY { expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [ , ... ] } ] [ SORT BY { expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [ , ... ] } ] [ CLUSTER BY { expression [ , ... ] } ] [ DISTRIBUTE BY { expression [, ... ] } ] [ WINDOW { named_window [ , WINDOW named_window, ... ] } ] [ LIMIT { ALL | expression } ]其中select_statement定义为:
SELECT [ hints , ... ] [ ALL | DISTINCT ] { [ [ named_expression | regex_column_names | star ] [ , ... ] | TRANSFORM (...) ] } FROM { from_item [ , ... ] } [ PIVOT clause ] [ UNPIVOT clause ] [ LATERAL VIEW clause ] [ ... ] [ WHERE boolean_expression ] [ GROUP BY expression [ , ... ] ] [ HAVING boolean_expression ] [ WINDOW clause ] [ QUALIFY boolean_expression ]4.2 核心子句速查
| 语法元素 | 语义要点 |
|---|---|
with_query | 在主查询前声明 CTE,便于抽象复用子查询块 |
hints | 指导优化器做连接策略选择与数据重分区 |
ALL/DISTINCT | 是否对结果去重,ALL为默认 |
named_expression | 带别名的表达式,语法为expression [[AS] alias] |
star | *选择 FROM 子句中一个或所有关系的列 |
from_item | 输入来源:表、JOIN、ASOF JOIN、PIVOT、UNPIVOT、表值函数、JSON_TABLE、内联表、UNNEST、子查询(可 LATERAL)、File |
WHERE | 基于布尔表达式过滤 FROM 结果 |
GROUP BY | 配合聚合函数(MIN/MAX/COUNT/SUM/AVG 等)分组聚合;聚合函数后可挂FILTER子句只对匹配行聚合 |
HAVING | 对 GROUP BY 产出行过滤;无 GROUP BY 时表示全局聚合 |
QUALIFY | 在窗口函数求值后过滤行;SELECT 列表或 QUALIFY 条件中必须至少含一个窗口函数,QUALIFY 内不允许聚合函数 |
ORDER BY/SORT BY | 前者对整个结果集全局排序,后者仅在每个分区内排序;两者互斥 |
CLUSTER BY/DISTRIBUTE BY | 前者等价于 DISTRIBUTE BY + SORT BY(重分区并排序),后者仅重分区;与 ORDER BY 互斥 |
LIMIT | 限制返回的最大行数,常与 ORDER BY 搭配产生确定性结果 |
4.3 CTE:公共表表达式
CTE 定义一个临时结果集,可在单条 SQL 语句作用域内被多次引用,语法为:
WITH common_table_expression [ , ... ]其中common_table_expression定义为:
expression_name [ ( column_name [ , ... ] ) ] [ AS ] [ [ NOT ] MATERIALIZED ] ( query )MATERIALIZED/NOT MATERIALIZED允许用户显式提示优化器是否物化 CTE 结果,这在重复引用同一子查询时可显著影响执行效率。
4.4 窗口函数
窗口函数基于一组行(窗口)计算每行的返回值,适用于移动平均、累计统计、相对位置取值等场景。其语法为:
window_function [ nulls_option ] OVER ( [ { PARTITION | DISTRIBUTE } BY partition_col_name = partition_col_val ( [ , ... ] ) ] { ORDER | SORT } BY expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [ , ... ] [ window_frame ] )- 窗口函数类型:排名类(
RANK | DENSE_RANK | PERCENT_RANK | NTILE | ROW_NUMBER)、分析类(CUME_DIST | LAG | LEAD | NTH_VALUE | FIRST_VALUE | LAST_VALUE)、聚合类(MAX | MIN | COUNT | SUM | AVG | ...)。 - nulls_option:
{ IGNORE | RESPECT } NULLS,默认RESPECT NULLS;仅LAG/LEAD/NTH_VALUE/FIRST_VALUE/LAST_VALUE支持IGNORE NULLS。 - window_frame:
{ RANGE | ROWS } { frame_start | BETWEEN frame_start AND frame_end },帧端点可为UNBOUNDED PRECEDING | offset PRECEDING | CURRENT ROW | offset FOLLOWING | UNBOUNDED FOLLOWING,省略frame_end时默认为CURRENT ROW。
4.5 检索语法的完整清单
SELECT 主文档 及其子页面覆盖了以下全部子句与构造:
- Common Table Expression
- CLUSTER BY Clause、DISTRIBUTE BY Clause
- GROUP BY Clause、HAVING Clause
- Hints
- Inline Table、UNNEST Clause、File
- JOIN、ASOF JOIN
- LIKE Predicate
- LIMIT Clause、OFFSET Clause
- ORDER BY Clause、SORT BY Clause
- Set Operators
- TABLESAMPLE
- Table-valued Function
- JSON_QUERY、JSON_ARRAY、JSON_TABLE、JSON_VALUE、JSON_EXISTS
- WHERE Clause
- Aggregate Function、Window Function
- CASE Clause
- PIVOT Clause、UNPIVOT Clause
- LATERAL VIEW Clause、LATERAL SUBQUERY
- TRANSFORM Clause
- star (*) Clause
其中regex_column_names是 Spark 较有特色的能力:当spark.sql.parser.quotedRegexColumnNames为 true 时,SELECT 中用反引号包裹的标识符会被解释为正则表达式。例如下面这条语句只会取到列c:
SELECT `(a|b)?+.+` FROM ( SELECT 1 as a, 2 as b, 3 as c )而TRANSFORM子句则提供 Hive 风格的 transform 查询:通过 fork 并运行用户指定的命令或脚本对输入做变换。
4.6 EXPLAIN:观察查询计划
Spark 提供EXPLAIN语句为给定语句生成逻辑/物理计划。默认仅输出物理计划,语法为:
EXPLAIN [ EXTENDED | CODEGEN | COST | FORMATTED ] statement- EXTENDED:依次生成 Parsed Logical Plan(未解析逻辑计划)、Analyzed Logical Plan(已解析并类型化)、Optimized Logical Plan(经优化规则集转换)与 Physical Plan。
- CODEGEN:生成语句对应的代码(如有)及物理计划。
- FORMATTED:输出物理计划大纲与节点详情两个部分。
- COST:当计划节点统计信息可用时,输出逻辑计划与统计信息。
典型输出(默认模式):
EXPLAIN select k, sum(v) from values (1, 2), (1, 3) t(k, v) group by k; +----------------------------------------------------+ | plan| +----------------------------------------------------+ | == Physical Plan == *(2) HashAggregate(keys=[k#33], functions=[sum(cast(v#34 as bigint))]) +- Exchange hashpartitioning(k#33, 200), true, [id=#59] +- *(1) HashAggregate(keys=[k#33], functions=[partial_sum(cast(v#34 as bigint))]) +- *(1) LocalTableScan [k#33, v#34] +----------------------------------------------------+可以看到sum被拆分为部分聚合(partial_sum)与最终聚合两段,Exchange hashpartitioning承担了跨节点 Shuffle 职责——这正是分布式聚合在物理计划层面的体现。
五、SQL 脚本语句:过程化逻辑
Spark SQL 提供 SQL 脚本(SQL scripting)能力,用于在 SQL 中执行过程化逻辑。语法层面,SqlBaseParser.g4 的singleCompoundStatement规则定义了BEGIN (NOT ATOMIC)? compoundBody? END的复合语句结构,compoundStatement则覆盖了变量赋值、IF/WHILE/REPEAT/LOOP/FOR 循环、CASE、LEAVE/ITERATE 跳转、DECLARE 等过程化构造,对应文档位于 control-flow 目录:
- CASE:多分支条件选择
- compound statement:BEGIN...END 复合语句块
- FOR:按查询结果或计数器循环
- IF:条件分支
- ITERATE:跳回循环开头继续迭代
- LEAVE:跳出循环或语句块
- LOOP:无条件循环
- REPEAT:先执行后判断的循环
- WHILE:先判断后执行的循环
SQL 脚本可与DECLARE VARIABLE、SET VAR、EXECUTE IMMEDIATE组合,在单个脚本内完成"声明变量 → 循环遍历 → 动态执行"的完整业务流程,适合在spark-sqlCLI、JDBC/ODBC 或 Spark Connect 客户端中直接提交多语句脚本。
六、辅助语句(Auxiliary Statements)
辅助语句覆盖资源管理、缓存、元数据查看、会话配置管理、表统计与刷新等运维与调试能力,共 30 条:
资源管理类
- ADD FILE、ADD JAR:向执行器分发文件/依赖
- LIST FILE、LIST JAR:列出已分发资源
缓存类
- CACHE TABLE:将表或查询结果缓存进内存(支持
LAZY与OPTIONS) - UNCACHE TABLE、CLEAR CACHE:清除缓存
- REFRESH TABLE、REFRESH、REFRESH FUNCTION:刷新缓存/函数元数据
元数据查看类(SHOW / DESCRIBE 系列)
- DESCRIBE DATABASE、DESCRIBE FUNCTION、DESCRIBE QUERY、DESCRIBE TABLE
- SHOW COLLATIONS、SHOW COLUMNS、SHOW CREATE TABLE、SHOW DATABASES、SHOW FUNCTIONS、SHOW PARTITIONS、SHOW TABLE EXTENDED、SHOW TABLES、SHOW TBLPROPERTIES、SHOW VIEWS
配置与会话管理类
- SET、RESET:查看/设置/重置 Spark 配置
- SET PATH:管理 SQL 中未限定名称的解析搜索路径
- SET VAR:给会话变量赋值
统计与动态执行类
- ANALYZE TABLE:收集表/列统计信息(
COMPUTE STATISTICS,可指定列) - EXECUTE IMMEDIATE:动态执行一条 SQL(支持
USING参数绑定)
语法文件中这些语句均有对应规则,例如ANALYZE TABLE identifierReference partitionSpec? COMPUTE STATISTICS (simpleIdentifier | FOR COLUMNS identifierSeq | FOR ALL COLUMNS)?、SHOW TABLES ((FROM | IN) identifierReference)? (LIKE? pattern=stringLit)? (AS JSON)?、CACHE LAZY? TABLE ...、UNCACHE TABLE (IF EXISTS)? ...、CLEAR CACHE等,展示了辅助语句在解析层如何被精确识别。
七、使用建议与延伸阅读
Spark SQL 的语法体系庞大但组织清晰:DDL 管结构、DML 管数据、SELECT 管检索、SQL 脚本管过程逻辑、辅助语句管运维与调试。实际使用时建议:
- 先定位再细读:不确定某条语句的写法时,先按本文的五大分类找到对应子文档(均在 docs 目录下),再阅读其中的完整语法、参数表与示例。
- 善用 EXPLAIN 调优:对任何复杂查询,先用
EXPLAIN EXTENDED观察 Parsed → Analyzed → Optimized → Physical 四层计划,确认过滤条件下推、连接策略、Shuffle 分布是否符合预期。 - 关注语句间的组合:CTE + 窗口函数 +
QUALIFY、MERGE INTO+ 分区裁剪、CACHE TABLE+REFRESH、变量声明 + SQL 脚本循环,这些组合能覆盖绝大多数数仓与数据湖上的典型场景。 - 验证运行环境前提:部分能力(如
WITH SCHEMA EVOLUTION、JSON 系列函数、SQL 脚本)与数据源 connector 能力及 Spark 版本相关,请以当前仓库 pom.xml 对应的版本行为为准。
继续深入可阅读 SQL Reference 总入口,其中按语法、数据类型、函数、错误条件等维度展开;若想了解语法背后的解析与优化实现,则可从 SqlBaseParser.g4 与 SparkSqlParser.scala 入手,对照本文第一节梳理的解析链路逐条追踪。
【免费下载链接】sparkApache Spark - A unified analytics engine for large-scale data processing项目地址: https://gitcode.com/gh_mirrors/sp/spark
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考