多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Apache Spark SQL DISTRIBUTE BY 子句详解:按表达式重分区与 CLUSTER BY 的区别

Apache Spark SQL DISTRIBUTE BY 子句详解:按表达式重分区与 CLUSTER BY 的区别 大数据数据分析批处理流处理机器学习图计算【免费下载链接】sparkApache Spark - A unified analytics engine for large-scale data processing项目地址https://gitcode.com/gh_mirrors/sp/spark点击查看免费下载导读本文是 Apache Spark SQL 语法参考系列中关于DISTRIBUTE BY子句的深度指南。DISTRIBUTE BY是 SELECT 查询组织结果阶段query organization的关键子句之一用于根据输入表达式重新分区数据拥有相同表达式取值的行会被聚集到同一个分区。与 CLUSTER BY 不同DISTRIBUTE BY不会在每个分区内对数据排序。读完本文你将掌握DISTRIBUTE BY的完整语法、参数语义、与SORT BY/CLUSTER BY/ORDER BY的组合规则、底层RepartitionByExpression的实现原理以及分区数相关的关键配置。本文对应的官方 SQL 参考文档为 docs/sql-ref-syntax-qry-select-distribute-by.md源码佐证主要来自 sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala、sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala 与 sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/plans/logical/basicLogicalOperators.scala。功能描述只重分区、不排序DISTRIBUTE BY子句基于输入表达式对数据进行重新分区repartition。它与CLUSTER BY子句最大的区别在于CLUSTER BY会在重分区之后对每个分区内部的数据进行排序而DISTRIBUTE BY不会。这一语义差异在解析器代码中有直接体现。在AstBuilder.withQueryResultClauses方法中见 AstBuilder.scalaSORT BY仅生成Sort(..., global false, query)只做分区内排序、不重分区DISTRIBUTE BY仅调用withRepartitionByExpression生成重分区逻辑计划不附加任何SortCLUSTER BY则等价于Sort(expressions.map(SortOrder(_, Ascending)), global false, withRepartitionByExpression(...))即重分区 分区内按表达式升序排序的组合。可见CLUSTER BY在实现上就是DISTRIBUTE BY与分区内排序按列升序的叠加因此每一条CLUSTER BY都可以改写为DISTRIBUTE BY ... SORT BY ...排序键与分区键相同。这从源码结构上印证了官方文档对二者差异的说明。语法DISTRIBUTE BY { expression [ , ... ] }DISTRIBUTE BY位于 SELECT 语句的查询组织QueryOrganization部分出现在FROM、WHERE、GROUP BY、HAVING等子句之后LIMIT/OFFSET之前。多个表达式之间用逗号分隔例如DISTRIBUTE BY age, name。参数说明参数说明expression一个或多个值、运算符和 SQL 函数的组合计算结果作为分区的依据。数据按表达式的哈希值分布到不同分区表达式取值相同的行落在同一分区中。完整示例官方文档提供了一个非常直观的对比示例。首先创建person表并插入 6 条数据CREATE TABLE person (name STRING, age INT); INSERT INTO person VALUES (Zen Hui, 25), (Anil B, 18), (Shone S, 16), (Mike A, 25), (John A, 18), (Jack N, 16); -- 将 shuffle 分区数降为 2以便更清楚地观察 DISTRIBUTE BY 的聚集与排序行为。 SET spark.sql.shuffle.partitions 2;第一步不加任何排序/分布子句的普通查询。结果没有确定性age 列的值并未聚集在一起SELECT age, name FROM person; ---------- |age| name| ---------- | 16|Shone S| | 25|Zen Hui| | 16| Jack N| | 25| Mike A| | 18| John A| | 18| Anil B| ----------第二步使用DISTRIBUTE BY age。相同 age 的行被聚集到同一分区输出中 age 相同的行彼此相邻但与CLUSTER BY不同分区内部不保证排序——例如 age 为 25 的分区内Zen Hui排在Mike A前面age 为 18 的分区内John A排在Anil B前面这并非有序排列SELECT age, name FROM person DISTRIBUTE BY age; ---------- |age| name| ---------- | 25|Zen Hui| | 25| Mike A| | 18| John A| | 18| Anil B| | 16|Shone S| | 16| Jack N| ----------注意示例中SET spark.sql.shuffle.partitions 2;是为了把数据压到更少的分区、便于观察聚集效果。实际生产环境中该参数默认值为 200同样年龄的行会被分布到这些分区中跨分区的聚集肉眼不可见但其哈希分布语义完全相同。底层原理RepartitionByExpression 逻辑计划从源码调用链看DISTRIBUTE BY的解析流程如下语法解析后AstBuilder的withQueryResultClauses识别出distributeBy非空调用withRepartitionByExpression(ctx, expressionList(distributeBy), query)AstBuilder.scalaAstBuilder基类中的withRepartitionByExpression默认抛出distributeByUnsupportedError表示该能力由具体方言解析器实现而 Spark 的实际 SQL 解析器SparkSqlParser覆写了该方法将其转换为逻辑计划节点SparkSqlParser.scala 中实现为RepartitionByExpression(expressions, query, None)RepartitionByExpression是 catalyst 中的逻辑计划算子basicLogicalOperators.scala其partitioning属性会根据分区数返回SinglePartition或HashPartitioning并且override def shuffle: Boolean true——意味着该算子必然触发一次真正的shuffle 重分区与Repartition/coalesce这类 RDD 语义操作不同。从源码注释可以进一步确认This method repartitions data using Expressions intooptNumPartitions... If nooptNumPartitionsis given, by default it partitions data intonumShufflePartitionsdefined inSQLConf, and could be coalesced by AQE.即DISTRIBUTE BY未显式指定分区数时默认按SQLConf中的numShufflePartitions对应spark.sql.shuffle.partitions默认 200进行分区同时分区数量还可能被Adaptive Query ExecutionAQE的 coalesce 优化进一步合并。与其他子句的组合与区别DISTRIBUTE BY属于查询结果组织子句家族同一查询中ORDER BY、SORT BY、DISTRIBUTE BY、CLUSTER BY四者的组合规则在解析器中是严格受控的组合解析行为依据 AstBuilder 代码效果仅ORDER BY生成Sort(..., global true)全局排序不重分区仅SORT BY生成Sort(..., global false)分区内排序不重分区仅DISTRIBUTE BY生成RepartitionByExpression重分区不排序SORT BYDISTRIBUTE BY先生成RepartitionByExpression再在外层包Sort(global false)AstBuilder.scala先按表达式重分区再在每个分区内排序仅CLUSTER BY按分区表达式生成RepartitionByExpression并包上按相同表达式升序的Sort(global false)重分区 分区内按列升序排序非法组合如ORDER BYSORT BY同用等抛出combinationQueryResultClausesUnsupportedErrorAstBuilder.scala解析报错几个实用要点CLUSTER BY可视为DISTRIBUTE BY 分区内排序的语法糖CLUSTER BY x等价于DISTRIBUTE BY x SORT BY x升序。若分区内需要自定义排序方向或排序键与分区键不同应显式写成DISTRIBUTE BY ... SORT BY ...ORDER BY是全局排序与DISTRIBUTE BY的角色不同需要整体有序输出时应使用ORDER BY即使它在物理上可能基于分布式排序实现管道运算符pipe operators场景在 SQL 管道语法| distribute by x中DISTRIBUTE BY同样被支持。测试用例 pipe-operators.sql 覆盖了| distribute by x、| cluster by x、| sort by x distribute by x等写法同时也验证了负例——DISTRIBUTE BY只能引用前一输入关系中的列名pipe-operators.sql。相关配置与运行前提使用DISTRIBUTE BY时以下配置与前提需要了解spark.sql.shuffle.partitions控制由 shuffle 引起的默认分区数默认值 200。DISTRIBUTE BY未显式指定目标分区数时即采用该值可通过SET命令调整AQE 的自动 coalesce在开启 Adaptive Query Execution 时最终落地的分区数可能小于spark.sql.shuffle.partitionsSpark 会在满足语义的前提下合并小分区因此观察到实际分区数略有差异属正常现象结果确定性DISTRIBUTE BY只保证相同表达式取值的行进入同一分区不保证分区内顺序也不保证分区间输出的整体顺序。若下游需要确定性排序必须配合SORT BY分区内有序或ORDER BY全局有序。常见问题FAQQ1DISTRIBUTE BY与CLUSTER BY的输出有何区别DISTRIBUTE BY只按表达式重新分区分区内行序不定CLUSTER BY在重分区后还会按同一表达式在分区内做升序排序输出更规整但多一次排序开销。Q2DISTRIBUTE BY会触发 shuffle 吗会。RepartitionByExpression逻辑算子的shuffle属性为true执行阶段必然经过一次按分区表达式哈希的 shuffle 重分区。Q3能否在一个查询里同时使用DISTRIBUTE BY和ORDER BY可以两者职责不同DISTRIBUTE BY控制数据分布ORDER BY控制最终输出顺序。注意解析器对同一类型子句的重复使用如两个ORDER BY会直接报错。Q4DISTRIBUTE BY的分区键必须是表中原有列吗不必是原始列任何合法的表达式均可作为分区键例如DISTRIBUTE BY age % 2会把奇偶年龄分散到不同分区。相关语句导航DISTRIBUTE BY属于 SELECT 查询组织子句体系与之配套的语法参考包括SELECT 主语句WHERE 子句GROUP BY 子句HAVING 子句ORDER BY 子句SORT BY 子句CLUSTER BY 子句LIMIT 子句OFFSET 子句CASE 子句PIVOT 子句UNPIVOT 子句LATERAL VIEW 子句赞分享大数据数据分析批处理流处理机器学习图计算【免费下载链接】sparkApache Spark - A unified analytics engine for large-scale data processing项目地址https://gitcode.com/gh_mirrors/sp/spark点击查看免费下载相关推荐Apache Spark SQL CLUSTER BY 子句完全指南分区内聚类与排序的语义、实现与实战Apache Spark SQL CLUSTER BY 子句完全指南分区内聚类与排序的语义、实现与实战 CLUSTER BY 是 Apache Spark S大数据数据分析批处理流处理机器学习图计算Apache Spark SQL 的 SORT BY 子句分区内排序语法、NULL 排序语义与底层实现解析Apache Spark SQL 的 SORT BY 子句分区内排序语法、NULL 排序语义与底层实现解析 输出文章 标签内的这篇技术指南完整讲解 Apac大数据数据分析批处理流处理机器学习图计算Apache Spark SQL GROUP BY 子句深度解析分组聚合、GROUPING SETS、ROLLUP 与 CUBE 实战指南Apache Spark SQL GROUP BY 子句深度解析分组聚合、GROUPING SETS、ROLLUP 与 CUBE 实战指南 Apache Sp大数据数据分析批处理流处理机器学习图计算创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表