ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Presto Release 0.257 深度解读:OFFSET 子句、array_position 增强与溢出内存修复实战指南

Presto Release 0.257 深度解读:OFFSET 子句、array_position 增强与溢出内存修复实战指南 Presto Release 0.257 深度解读OFFSET 子句、array_position 增强与溢出内存修复实战指南【免费下载链接】prestoThe official home of the Presto distributed SQL query engine for big data项目地址: https://gitcode.com/gh_mirrors/pre/presto本指南基于 Presto 官方发布说明 release-0.257.rst 编写并结合当前仓库源码对每个变更点进行底层原理与实战配置层面的展开。读完本文你将掌握如何启用并正确使用新增的OFFSET子句、如何利用array_position的“第 n 次出现”定位能力、以及 0.257 中围绕 Spill 内存、JOIN 死锁、Avro/Kerberos 与动态裁剪等关键修复的来龙去脉并了解如何安全地规划升级。一、Release 0.257 概览Presto Release 0.257 是一次以“稳定性修复 查询能力增强”为主基调的版本。整体变更分为两大块General Changes通用引擎变更涵盖内存溢出修复、Spill 场景下的死锁修复、array_position函数增强、相关子查询correlated subquery支持复杂表达式、以及全新的OFFSET子句支持等。Hive ChangesHive 连接器变更修复 Avro 格式表在 Kerberos 启用的 HDFS 上读取 schema 的缺陷以及 Hive 分区动态裁剪对 null 键的处理。下文将按“新增能力 → 稳定性修复 → Hive 修复”的顺序逐项展开并在每个主题下给出仓库中的源码与测试依据。二、重点新能力OFFSET 子句这是 0.257 中最具实用价值的功能点。发布说明原文为Add support for theOFFSETclause in SQL query expressions. This feature can be enabled by setting the session propertyoffset_clause_enabledor configuration propertyoffset-clause-enabledtotrue.也就是说OFFSET 子句从 0.257 开始正式纳入 SQL 语法支持但默认处于关闭状态需要显式开启后才能使用。2.1 如何启用 OFFSET启用方式有两种任选其一方式一Session 级启用单查询生效SET SESSION offset_clause_enabled true; SELECT * FROM orders ORDER BY orderkey OFFSET 10 ROWS;方式二配置级启用全局生效在协调节点Coordinator与工作节点Worker的config.properties中加入offset-clause-enabledtrue从源码看该配置项定义于 FeaturesConfig.javaConfig(offset-clause-enabled) ConfigDescription(Enable support for OFFSET clause) public FeaturesConfig setOffsetClauseEnabled(boolean offsetClauseEnabled) { this.offsetClauseEnabled offsetClauseEnabled; return this; }而对应的 Session 属性在 SystemSessionProperties.java 中声明为OFFSET_CLAUSE_ENABLED offset_clause_enabled并在注册处同文件 L1584-L1587与FeaturesConfig.isOffsetClauseEnabled()绑定默认值取配置项的值。值得注意的是在较新的代码中该 Session 属性注册时默认值直接取featuresConfig.isOffsetClauseEnabled()意味着只要配置文件开了开关所有会话默认即启用。2.2 SQL 语法层面OFFSET 长什么样在 0.257 中OFFSET 的语法形态由 ANTLR 文法 SqlBase.g4 定义(ORDER BY sortItems)? (OFFSET offsetINTEGER_VALUE (ROW | ROWS)?)? (LIMIT limitINTEGER_VALUE | FETCH FIRST limitINTEGER_VALUE (ROW | ROWS) ONLY)?也就是说OFFSET出现在ORDER BY之后、LIMIT之前行数必须是整数字面量且可以带可选的ROW或ROWS单位如OFFSET 10 ROWS、OFFSET 10 ROW、OFFSET 10均合法。解析阶段由 AstBuilder.java 处理OptionalOffset offset Optional.empty(); if (context.OFFSET() ! null) { offset Optional.of(new Offset( Optional.of(getLocation(context.OFFSET())), getTextIfPresent(context.offset).orElseThrow(() - new IllegalStateException(Missing OFFSET row count)))); }生成的 AST 节点Offset作为Query树的一个组成部分见 Query.java并在格式化回 SQL 时输出为OFFSET count ROWS见 SqlFormatter.java。2.3 语义校验行数必须非负在分析阶段StatementAnalyzer.java 会对 OFFSET 行数做合法性校验违反时抛出INVALID_OFFSET_ROW_COUNT语义错误throw new SemanticException(INVALID_OFFSET_ROW_COUNT, node, Invalid OFFSET row count: %s, node.getRowCount()); throw new SemanticException(INVALID_OFFSET_ROW_COUNT, node, OFFSET row count must be greater or equal to 0 (actual value: %s), rowCount);即OFFSET 的行数必须是大于等于 0 的整数。2.4 执行计划层面OffsetNode 与优化规则逻辑计划中使用专门的OffsetNode表示跳过前 N 行节点内部保存count字段并要求count 0见 OffsetNode.java。围绕该节点0.257 引入了一组迭代优化规则ImplementOffset.java把OffsetNode改写为Project → Filter(rowNumber x) → RowNumber三节点结构。其 Javadoc 明确说明该改写依赖RowNumberNode保持输入顺序的特性因此当查询含ORDER BY时排序后的行顺序会被保留再裁掉前 x 行。PushLimitThroughOffset.java当LIMIT与OFFSET共存时将LIMIT下推经过OFFSETLIMIT n变为LIMIT n offset从而让上游尽早裁剪数据。PushOffsetThroughProject.java将OFFSET下推穿透Project节点减少中间结果。同时SimplifyPlanWithEmptyInput等优化器也会感知OffsetNode见 SimplifyPlanWithEmptyInput.java在输入为空时提前化简。重要ImplementOffset在应用时会检查 Session 属性若未开启 OFFSET 支持会直接抛出PrestoException错误码NOT_SUPPORTED错误信息 Offset support is not enabled。这一点在测试 TestImplementOffset.java 中有完整覆盖Test(expectedExceptions PrestoException.class, expectedExceptionsMessageRegExp Offset support is not enabled) public void testOffsetClauseDisabled()而开启属性后OFFSET 2会被改写为row_num BIGINT 2的 Filter 加 RowNumber 计划见同文件 testReplaceOffsetOverValues。2.5 OFFSET 使用示例-- 开启会话级开关 SET SESSION offset_clause_enabled true; -- 跳过前 10 行取后续数据 SELECT orderkey, totalprice FROM orders ORDER BY orderkey OFFSET 10 ROWS; -- OFFSET 与 LIMIT 组合实现分页第 3 页每页 20 条 SELECT * FROM orders ORDER BY orderkey OFFSET 40 ROWS LIMIT 20; -- 不带 ROWS/ROW 单位也合法 SELECT name FROM nation OFFSET 2;在 0.257 中该能力默认关闭升级后如需使用请务必先设置offset-clause-enabledtrue全局或在会话中开启offset_clause_enabled否则会得到 Offset support is not enabled 错误。三、重点新能力array_position 支持“第 n 次出现”发布说明原文Add support to find the n-th instance in :func:!array_position.3.1 功能语义array_position(array(T), element)原本只能返回元素第一次出现的位置1-based未找到返回 0。0.257 为其增加了第三个可选参数instance用于定位第 n 次出现instance 0从数组头部向尾部扫描返回第 n 次出现的位置instance 0从数组尾部向头部扫描返回倒数第 n 次出现的位置instance 0非法抛出INVALID_FUNCTION_ARGUMENT异常若不足 n 次出现返回 0。3.2 源码实现新增实现位于 ArrayPositionWithIndexFunction.java与原有 ArrayPositionFunction.java 共用array_position函数名重载并在 BuiltInTypeAndFunctionNamespaceManager.java 中注册。核心扫描逻辑以 LONG 元素重载为例L91-L120int size array.getPositionCount(); int instancesFound 0; if (instance 0) { throw new PrestoException(INVALID_FUNCTION_ARGUMENT, array_position cannot take a 0-valued instance argument.); } int startIndex instance 0 ? 0 : size - 1; int stopIndex instance 0 ? size : -1; int stepSize instance 0 ? 1 : -1; instance Math.abs(instance); for (int i startIndex; i ! stopIndex; i stepSize) { if (!array.isNull(i)) { long arrayValue type.getLong(array, i); Boolean result (Boolean) equalMethodHandle.invoke(arrayValue, element); checkNotIndeterminate(result); if (result) { instancesFound; if (instancesFound instance) { return i 1; // result is 1-based (instead of 0) } } } } return 0;实现细节值得注意方向控制通过instance的正负决定起点、终点和步长负数场景从size - 1反向扫描实现“倒数第 n 次”。类型泛化同一函数针对 boolean、long、double、Slice 等类型提供多个SqlType重载T泛型 TypeParameter元素相等性通过OperatorDependency(operator EQUAL)注入的equalMethodHandle比较支持任意可比较的数组元素类型。NULL 跳过数组中的 NULL 元素被跳过不参与计数。1-based 返回命中时返回i 1与 SQL 数组下标习惯一致未命中返回 0。3.3 使用示例SELECT array_position(ARRAY[a, b, a, c, a], a); -- 返回 1第一次出现 SELECT array_position(ARRAY[a, b, a, c, a], a, 2); -- 返回 3第二次出现 SELECT array_position(ARRAY[a, b, a, c, a], a, 3); -- 返回 5第三次出现 SELECT array_position(ARRAY[a, b, a, c, a], a, -1); -- 返回 5倒数第一次出现 SELECT array_position(ARRAY[a, b, a, c, a], a, -2); -- 返回 3倒数第二次出现 SELECT array_position(ARRAY[a, b], z, 1); -- 返回 0未找到 SELECT array_position(ARRAY[a, b], a, 0); -- 报错0 is an invalid instance position for array_position该能力对“重复事件序列中定位特定次数事件”的场景如日志分析、时序数据去重取第 N 条非常实用且对 BOOLEAN、BIGINT、DOUBLE、VARCHAR 等主流类型均有重载支持。四、General Changes 稳定性与正确性修复0.257 同时包含一批针对 Spill、内存跟踪与表达式正确性的修复建议升级用户在压测时重点回归以下场景。4.1 Spill 相关的三个修复Fix queries failing withEXCEEDED_LOCAL_MEMORY_LIMITerror due to incorrect memory tracking while reading spilled data.Fix deadlock for queries withJOINandLIMITwith spilling enabled.Improve memory usage of queries spilling in the join operator.这三条均围绕Spill溢写机制读取溢写数据时内存跟踪错误导致EXCEEDED_LOCAL_MEMORY_LIMIT0.256 及更早版本中算子从磁盘回读溢写数据如排序、聚合、JOIN 的 spill file时其内存占用未被正确计入本地内存池导致查询被误判为超限而失败。0.257 修正了该路径的内存记账消除了这类“假阳性”超限。JOIN LIMIT Spill 组合下的死锁当查询同时包含 JOIN 与 LIMIT 且开启了 Spill 时可能因算子间相互等待如 JoinOperator 等待 spill 完成、LimitOperator 等待输入而进入死锁。0.257 修复了该调度时序问题。JOIN 算子溢写内存优化改进了 Hash Join 在溢写场景下的内存分配策略减少不必要的缓冲占用。建议升级后在开启spill-enabledtrue的环境中对 JOIN、GROUP BY、ORDER BY 混合 LIMIT 的查询做回归验证。4.2 表达式正确性同一变量多个 IS NULL 判断Fix query failures due to expressions with multipleis nullchecks on the same variable.修复了同一表达式如 CASE、复杂 WHERE 条件中对同一个变量多次做IS NULL判断时可能触发的查询失败。该问题与常量折叠、IS NULL谓词下推及去重优化相关0.257 修正了这类表达式的求值逻辑确保如WHERE (a IS NULL) OR (a IS NOT NULL AND b 1)这类写法稳定执行。4.3 查询计划可读性表达式打印更接近合法 SQLImprove expressions printed in query plans to be closer to valid SQL.0.257 改进了EXPLAIN输出中表达式尤其是一元/二元运算、类型转换与函数调用的格式化逻辑使计划中的表达式更接近可直接执行的合法 SQL 形态。这对使用EXPLAIN (FORMAT JSON)/EXPLAIN ANALYZE做性能分析与问题排查的团队是直接收益——计划更易读、更易复制回放。4.4 相关子查询支持相关条件中的复杂表达式Add support for correlated subqueries with complex expressions in the correlation.相关子查询correlated subquery此前要求相关列correlation为简单列引用0.257 扩展为允许在相关条件中使用复杂表达式。例如SELECT o.custkey, (SELECT max(l.extendedprice) FROM lineitem l WHERE l.orderkey o.orderkey 100) AS adjusted_max FROM orders o;这里子查询的相关条件l.orderkey o.orderkey 100中出现了算术表达式o.orderkey 100而不仅是o.orderkey0.257 起的分析器与去关联decorrelation流程可以正确处理此类形态。这条能力的价值在于许多“基于派生键关联”的业务 SQL如 join key 需要变换从此可以直接写成相关子查询而不必改写成 JOIN 或 CTE。五、Hive 连接器修复Fix a bug in reading Avro format table with schema located in a Kerberos enabled HDFS compliant filesystem.Fix dynamic pruning for null keys in hive partition.5.1 Avro 表 Kerberos HDFS 读取修复在 Kerberos 启用的 HDFS 兼容文件系统上若 Avro 表的 schema 存放在 HDFS 中avro.schema.url指向 HDFS 路径0.257 之前存在读取缺陷涉及 delegate 文件系统的认证上下文传递导致 schema 拉取失败或表读取异常。0.257 修复了该场景下通过 HiveMetastore/文件系统访问 Avro schema 的路径使得“Kerberos 安全集群 Avro schema 外置”的组合可以正常工作。5.2 分区动态裁剪null 键修复修复了 Hive 分区动态裁剪dynamic partition pruning在分区键为 NULL时的缺陷。此前当查询针对分区列使用可推导为 NULL 的过滤条件或裁剪值包含 NULL时动态裁剪可能产生错误的裁剪集合或遗漏分区。0.257 修正了对 null 分区键的裁剪处理避免结果缺失或多余扫描。六、升级与回归建议结合上述变更升级到 0.257 前后建议按如下清单操作功能开关若业务需要使用OFFSET在config.properties中配置offset-clause-enabledtrue若只想局部试用使用SET SESSION offset_clause_enabled true;。注意两处配置名的连字符/下划线区别。Spill 场景回归对开启spill-enabled的集群重点回归JOIN/GROUP BY/ORDER BY与LIMIT组合的查询确认不再出现死锁与EXCEEDED_LOCAL_MEMORY_LIMIT。Kerberos 集群回归Hive 使用 Avro 表且 schema 存放于 HDFS 的表在安全集群上验证可正常读取。分区裁剪回归对分区列为 NULL 的场景如WHERE partition_col IS NULL或裁剪结果含 NULL做正确性验证。函数行为确认array_position新增了第三参数重载原有两参数调用行为不变可放心兼容新增的“第 n 次 / 倒数第 n 次”语义可直接用于业务 SQL。七、总结Presto Release 0.257 在查询表达能力与稳定性两个维度都有实质提升OFFSET 子句补齐了标准 SQL 分页语法配合LIMIT使用其实现OffsetNodeImplementOffset/PushLimitThroughOffset/PushOffsetThroughProject规则 RowNumber改写在源码与单测中均有完整闭环可放心启用array_position三参数重载提供了正/反向“第 n 次出现”定位能力实现上对多种元素类型泛化支持NULL 语义清晰多个 Spill 内存与死锁修复显著改善了开启溢写场景下的查询稳定性Hive 侧的 Avro/Kerberos 与动态裁剪 null 键修复则让安全集群与边界数据场景更加可靠。如需深入实现细节可继续阅读FeaturesConfig.java、ImplementOffset.java、ArrayPositionWithIndexFunction.java以及对应测试 TestImplementOffset.java 与 TestPushLimitThroughOffset.java。【免费下载链接】prestoThe official home of the Presto distributed SQL query engine for big data项目地址: https://gitcode.com/gh_mirrors/pre/presto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表