ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Presto Release 0.154 技术解读:规划器修复、窗口函数优化与 DESCRIBE INPUT 新能力

Presto Release 0.154 技术解读:规划器修复、窗口函数优化与 DESCRIBE INPUT 新能力 大数据数据库后端【免费下载链接】prestoThe official home of the Presto distributed SQL query engine for big data项目地址https://gitcode.com/gh_mirrors/pre/presto点击查看免费下载导读Release 0.154 是 Presto 演进历程中的一次典型的稳定性 新功能双轨发布一方面集中修复了规划器Planner在处理JOIN、IN子查询、bucketed 表写入等场景下的错误结果与异常失败并显著优化了窗口函数的执行性能另一方面为运维侧引入code-cache-collection-threshold配置项控制 JVM Code Cache 回收为开发者新增CREATE TABLE ... LIKE与DESCRIBE INPUT两项 SQL 能力同时修复了 Hive Metastore 缓存 TTL 永不失效的严重问题。阅读本文后你将掌握这些修复背后的规划原理、新配置的调优方法、新 SQL 语句的完整用法以及对应的源码级实现证据。一、General Changes从查询错误修复到新 SQL 能力1.1 修复 JOIN 查询中对非空输入返回 null函数的规划错误原始记录修复了一个规划问题该问题可能导致包含在非空输入上返回 null 的函数的JOIN查询产生错误结果。技术分析这类问题的根源通常出现在逻辑计划优化阶段——当规划器对JOIN进行谓词下推、null传播或 join 重排时若函数满足对非空输入返回 null例如某些可空性相关函数优化器可能基于错误的可空性假设改写谓词或关联条件从而在运行时产生与语义不符的结果集。此类问题难以通过单条查询复现属于典型的静默错误结果型缺陷。0.154 的修复落在规划环节保证改写后的计划与 SQL 语义严格一致。从源码结构看此类修复通常与 predicate-pushdown / join 优化器 目录下的优化器如PredicatePushDown、AddExchanges等相关这些优化器负责在计划重写时维护符号与谓词的可空性约束。1.2 修复IN谓词中无关联子查询的规划回归原始记录修复了一个回归问题该回归会导致某些包含IN谓词中无关联子查询uncorrelated subqueries的查询在规划阶段失败。技术分析WHERE x IN (SELECT ...)中的子查询若与外部查询无关联uncorrelated规划器通常会将其物化为独立算子再与主查询进行semi-join或join结合。此前版本中某次优化引入了回归导致这类常见写法在analyze/plan阶段直接抛错、查询无法执行。0.154 修复了该路径恢复了无关联子查询的标准规划流程。相关证据此类重写逻辑位于 presto-main-base 的 sql/rewrite 与 sql/planner 目录IN子查询的展开与去关联由分析器和规划器协同完成。1.3 修复写 bucketed 表时的 Input symbols do not match output symbols 错误原始记录修复了写入 bucketed 表时可能出现的Input symbols do not match output symbols错误。源码证据该错误信息在当前仓库中的确切出处是 ExchangeNode.javacheckArgument(inputs.stream().allMatch(inputVariables - inputVariables.size() partitioningScheme.getOutputLayout().size()), Input symbols do not match output symbols);ExchangeNode是分布式查询计划中负责数据交换GATHER / REPARTITION / REPLICATE 等的核心节点见同文件 ExchangeNode 类型定义。当向 bucketed 表写入时计划器需要为每个分区bucket构造匹配PartitioningScheme输出布局的输入符号列表若某条写入路径的输入符号数量与输出布局不一致上述checkArgument就会触发。0.154 修复了该路径上符号构造的缺陷使 bucketed 写入不再因符号不匹配而失败。1.4 修复 Requested array size exceeds VM limit 触发的 JVM OOM 处理原始记录修复了可能触发Requested array size exceeds VM limit错误并进而引发 JVMOutOfMemoryError处理的问题。技术分析Requested array size exceeds VM limit是 JVM 在尝试分配超过平台限制的数组时抛出的OutOfMemoryError子类错误。在 Presto 中这类错误通常源于某个计算在内存中构造了超大数组例如分组键、字典编码或页构建逻辑中对行数/桶数的错误估计。修复前该错误会进入通用 OOM 处理路径可能导致查询被杀死或触发内存保护机制误判修复后查询能够以更合理的错误路径失败或正确处理。说明本条目对应 0.154 版本的历史修复当前仓库中未再保留该错误字符串的源码引用属于已合入并演化的修复故以上分析以 release 记录与 JVM 语义为依据。1.5 窗口函数性能优化相同分区/排序、不同 frame 规格原始记录提升了分区与排序完全相同、但 frame 规格frame specification不同的窗口函数的性能。技术分析一个查询中常出现多个窗口函数共享相同的PARTITION BY与ORDER BY例如同时计算ROW_NUMBER() OVER (...)、SUM(...) OVER (... ROWS BETWEEN ...)等多个窗口但各自的 frameROWS/RANGE边界不同。0.154 通过让这些窗口函数共享同一次排序与分区计算仅在 frame 应用阶段区分处理从而避免为每个窗口重复执行昂贵的排序/分区开销。这是典型的计算共享computation reuse优化对报表类、多窗口聚合类查询收益显著。相关实现窗口节点在计划层由 WindowNode 表示相关优化逻辑可参考 WindowFilterPushDown.java 与 WindowNodeUtil.java。1.6 新增配置code-cache-collection-threshold主动回收 JVM Code Cache原始记录新增code-cache-collection-threshold配置用于控制 Presto 何时尝试强制回收 JVM Code Cache并将默认阈值调低至40%。技术分析Presto 依赖 Bytecode 动态生成执行计划涉及大量的即时编译长时间运行后 JVM 的 Code Cache 可能被占满进而触发CodeCache is full警告、编译被禁用甚至影响执行性能。0.154 引入的该配置让 Presto 在 Code Cache 使用率超过阈值时主动发起回收释放已失效的编译代码同时将默认阈值从更高值下调到40%更早介入回收降低 Code Cache 打满的风险。配置方式在etc/config.properties中code-cache-collection-threshold40适用前提该配置为 0.154 引入的历史配置项默认阈值为40%。当前版本仓库的源码中已不再保留该配置的解析逻辑全仓库搜索仅 release 文档引用如需使用请以对应版本分支的文档为准。1.7 新增CREATE TABLE ... LIKE按已有表结构建表原始记录新增对CREATE TABLE中使用LIKE的支持。完整语法与语义依据 create-table.rstCREATE TABLE new_table ( ... LIKE existing_table_name [ { INCLUDING | EXCLUDING } PROPERTIES ] ... )关键行为来自 create-table.rstLIKE子句将已有表的全部列定义复制到新表可在一条CREATE TABLE中书写多个LIKE子句从而合并多张表的列。指定INCLUDING PROPERTIES时已有表的表属性如表格式、分区属性等一并复制到新表若WITH子句中指定了同名属性则以WITH的值为准覆盖。默认行为是EXCLUDING PROPERTIES不复制属性。INCLUDING PROPERTIES最多只能在一张LIKE表上使用。示例来自 create-table.rstCREATE TABLE bigger_orders ( another_orderkey bigint, LIKE orders, another_orderdate date )该语法让从已有表复制结构 追加自定义列这类建表需求变得一行式可读避免了手工罗列全部列定义。1.8 新增DESCRIBE INPUT查看预处理语句的输入参数要求原始记录新增对DESCRIBE INPUT的支持用于描述预处理语句prepared statement输入参数的要求。语法依据 describe-input.rstDESCRIBE INPUT statement_name功能列出预处理语句的全部输入参数包含每个参数的位置Position与类型Type无法推断出类型的参数显示为unknown。示例一含三个参数的查询来自 describe-input.rstPREPARE my_select1 FROM SELECT ? FROM nation WHERE regionkey ? AND name ?; DESCRIBE INPUT my_select1;输出Position | Type -------------------- 0 | unknown 1 | bigint 2 | varchar (3 rows)注意第一个?位于SELECT投影列因缺少类型约束上下文其类型被推断为unknown而regionkey与name因与已知列比较可推断为bigint与varchar。示例二无参数查询来自 describe-input.rstPREPARE my_select2 FROM SELECT * FROM nation; DESCRIBE INPUT my_select2;输出Position | Type ----------------- (0 rows)源码实现DESCRIBE INPUT的完整执行路径可从 DescribeInputRewrite.java 追溯从会话中取出预处理语句的 SQL 文本session.getPreparedStatement(...)L121用SqlParser重新解析该语句并通过Analyzer.analyzeSemantic(...)做语义分析L122-L126通过ParameterExtractor.getParameters(statement)提取全部参数L131逐个参数通过analysis.getCoercion(parameter)获取推断类型若类型为空则回退为UNKNOWN最终以Position | Type两列结果集返回L155-L165——注意参数位置从0开始计数若无参数则构造一个空结果集LIMIT 0返回L136-L139。在语法解析层AST 节点定义于 DescribeInput.java。该语句对 JDBC 驱动、查询工具等需要预编译 SQL 参数化场景尤其有价值客户端可在EXECUTE前确认占位符的数量与类型从而正确绑定参数。二、Hive Changes修复 Metastore 缓存 TTL 永不失效原始记录修复了 Metastore 缓存 TTL 的处理问题。随着按事务per-transaction缓存的引入缓存超时在每次访问后被重置导致缓存条目可能永远不过期。技术分析这是一个典型的缓存失效语义 bug——在引入 per-transaction 缓存后每次缓存命中都会续期刷新超时计时相当于把 TTL 语义从绝对过期退化成了滑动过期只要条目被持续访问就永不失效。其后果是Hive 表/分区元数据的变更如新增分区、修改 schema可能长期不被 Presto 感知出现查询读到陈旧元数据的问题。当前仓库中的缓存配置体系来自 MetastoreClientConfig.java已演进为一套细粒度控制核心配置项包括# 全局默认 TTL 与刷新间隔0 表示不缓存/不刷新 hive.metastore.cache.ttl0s hive.metastore.cache.refresh-interval0s # 按缓存类型如 table/partition 等分别指定 TTL 与刷新间隔 hive.metastore.cache.ttl-per-cache-type... hive.metastore.cache.refresh-interval-per-cache-type... # 缓存容量上限 hive.metastore.cache.maximum-size10000 hive.metastore.cache.per-transaction-maximum-size1000 # 启用/禁用指定缓存类型 hive.metastore.cache.enabled-caches... hive.metastore.cache.disabled-caches...源码佐证缓存规格对象 MetastoreCacheSpec.java 中定义了cacheTtlMillis缓存 TTL 毫秒值等字段enabled(...)工厂方法接收cacheTtlMillis、refreshIntervalMillis、maximumSize三个参数L16-L42缓存类型table / partition 等与作用域按事务 / 跨事务的枚举定义于AbstractCachingHiveMetastore缓存统计与手动失效能力见 HiveMetastoreCacheStats.java 与 InvalidateMetastoreCacheProcedure.java。0.154 修复的核心即确保 TTL 是自缓存条目创建/加载起算的绝对过期时间访问命中不再重置计时从而让过期条目能够按预期被清理并重新拉取保证元数据的新鲜度。三、升级与验证建议验证 JOIN / IN 类查询升级到 0.154 后建议回归测试包含多表JOIN与x IN (SELECT ...)无关联子查询形态的线上慢查询确认结果集与升级前一致、且不再出现规划期异常。窗口函数多窗口场景对同时使用多个窗口函数相同PARTITION BY/ORDER BY、不同 frame的报表查询做性能对比验证排序共享优化带来的收益。新 SQL 语法试用在测试环境执行CREATE TABLE ... LIKE与PREPARE/DESCRIBE INPUT/EXECUTE组合确认建表结构与参数类型推断符合预期。Hive 元数据缓存若配置了 metastore 缓存 TTL升级后可通过DESCRIBE/SHOW PARTITIONS观察元数据变更的生效延迟确认过期条目能被正常清理。小结Release 0.154 通过 8 项通用改进与 1 项 Hive 修复同时兼顾了正确性、性能与可用性规划器层面的 JOIN/IN 修复保障了查询语义正确窗口函数计算共享与 Code Cache 主动回收提升了长时运行的稳定性CREATE TABLE ... LIKE与DESCRIBE INPUT则补齐了建表与预处理语句诊断的 SQL 能力而 Hive Metastore 缓存 TTL 的修复避免了陈旧元数据带来的隐性数据不一致。对仍运行在 0.154 附近版本的集群本文所列配置与验证清单可作为升级、调优与排障的直接参考。赞分享大数据数据库后端【免费下载链接】prestoThe official home of the Presto distributed SQL query engine for big data项目地址https://gitcode.com/gh_mirrors/pre/presto点击查看免费下载相关推荐Presto Release 0.130 技术解读性能回归修复、map_concat 新函数与列式字典优化Presto Release 0.130 技术解读性能回归修复、map_concat 新函数与列式字典优化 Presto 0.130 是一个以 性能与查询优化大数据数据库后端Presto Release 0.67 解析ConnectorSplitSource SPI 破坏性变更、Hive 资源泄漏修复与窗口函数规划修复Presto Release 0.67 解析ConnectorSplitSource SPI 破坏性变更、Hive 资源泄漏修复与窗口函数规划修复 Prest大数据数据库后端Presto Release 0.90 技术解读规划器改进、新聚合函数与关键配置项Presto Release 0.90 技术解读规划器改进、新聚合函数与关键配置项 本文以 Presto 0.90 版本的官方发布说明为主体逐项解读该版本在大数据数据库后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进