资讯详情

资讯详情

Apache Calcite 1.22.0 发布详解:SQL Hints、Redis 适配器与函数能力扩展

后端数据库【免费下载链接】calciteApache Calcite项目地址https://gitcode.com/gh_mirrors/ca/calcite点击查看免费下载Apache Calcite 1.22.0 于 2020 年 3 月 5 日发布这是继 1.21.0 之后历时五个月的重大版本累计解决了超过 250 个 issue涵盖大量新特性、通用改进与缺陷修复。本指南以官方发布公告为核心结合当前仓库源码与文档深入解读该版本的三大亮点——面向关系表达式的 SQL Hints、全新 Redis 适配器、以及 Oracle/MySQL 函数扩充并梳理其中的关键 Bug 修复与破坏性变更帮助读者理解这些能力在 Calcite 中的落地方式与实际用法。一、版本概览本次发布的核心亮点包括SQL Hints 支持CALCITE-482可为不同类型的关系表达式Relational Expression附加查询提示全新 Redis 适配器CALCITE-3510允许直接用 SQL 查询 Redis 中的实时数据更多 Oracle 与 MySQL 函数如 Oracle XML 函数CALCITE-3579、CALCITE-3580与 MySQL 数学函数CALCITE-3684、CALCITE-3695、CALCITE-3707。同时修复了若干重要缺陷例如RelSet合并时元数据缓存的罕见问题、GROUP_ID结果错误、CORRELATE行数估计恒为 1 的问题以及DECIMAL取模运算的精度推断错误。二、SQL Hints从解析到规划器的完整链路SQL Hints 是 1.22.0 最受关注的新特性它让用户可以在不改写 SQL 逻辑的前提下向优化器传递查询级别的建议。该特性在 site/_docs/history.md 的 1.22.0 章节中被列为头条特性涉及 CALCITE-482、CALCITE-3631Calc 支持、CALCITE-3590Aggregate 支持、CALCITE-3781HintStrategy 可指定被排除的规划规则、CALCITE-3719提示选项校验器等多个子任务。2.1 语法形态与解析Calcite 的 hint 语法兼容主流数据库习惯例如SELECT /* hint1, hint2(a1, b2) */ * FROM emp /* hint3(5, x) */ JOIN dept /* hint4(cid), hint5 */其解析产物是SqlHint节点。从该类源码可以看出一个 hint 由三部分组成namehint 名称SqlIdentifieroptions选项列表SqlNodeListoptionFormat选项的三种格式——ID_LIST简单标识符列表、LITERAL_LIST字面量列表、KV_LIST键值对列表由getOptionList()与getOptionKVPairs()分别解析。因此在同一个 hint 内既可以写hint2(a1, b2)这样的键值对也可以写hint3(5, x)这样的字面量列表。解析后的 hint 会挂载到 SQL 树中并在 SQL 转关系表达式SqlToRel阶段转换为RelHint。2.2 核心模型RelHint 与 HintStrategyTableRelHintcore/src/main/java/org/apache/calcite/rel/hint/RelHint.java是 hint 在关系代数层的载体其字段包括hintNamehint 名称listOptions/kvOptions分别保存列表形式与键值对形式的选项两者被设计为可携带相同信息inheritPath整数列表用于支持 hint 在规则变换过程中的覆盖/继承语义——当某个关系表达式被改写为其他类型节点时hint 可以按路径决定是否随节点传播。所有 hint 必须注册到HintStrategyTablecore/src/main/java/org/apache/calcite/rel/hint/HintStrategyTable.java中才能生效。该表的职责见其类注释包括三件事判断给定 hint 是否已注册判断哪些 hint 适合挂载到给定的关系表达式上通过HintPredicate谓词校验 hint 选项是否合法通过HintOptionChecker。HintStrategyTable是不可变的通过builder()构建hint 名称的匹配不区分大小写Key内部统一转为小写。默认的HintErrorLogger在校验失败时只记录警告日志而不抛出异常避免无效 hint 阻断查询。apply()方法会过滤掉不适用于当前节点类型的 hintvalidateHint()则负责注册与选项校验。此外isRuleExcluded()支持通过 hint 指定排除某些规划规则若某 hint 声明了excludedRules则当节点带有该 hint 时Hintable上对应的规则将不再匹配如果同时指定了converterRules还会先验证转换是否可行isDesiredConversionPossible。这为规划器提供了细粒度的规则控制手段。2.3 Hint 在规划与规则传播中的行为Hintablecore/src/main/java/org/apache/calcite/rel/hint/Hintable.java接口让各类关系表达式都能携带 hints。从源码结构看Project、TableScan、Calc、Aggregate、Join、Sort、Filter、Window、Union、SetOp、Values、Snapshot等逻辑节点均已实现该接口。配套的测试类 SqlHintsConverterTest 覆盖了 hint 的解析、校验、继承与规则排除等场景其中可以见到更复杂的用法select /* resource(parallelism3), repartition(10) */ empno from (select /* resource(mem20Mb)*/ empno, ename from emp);以及select /* index(idx1), no_hash_join */ * from emp /* index(empno) */后者展示了表级 hint 与查询级 hint 的共存方式。1.22.0 还专门修复了规则变换后 hint 传播的问题CALCITE-3649确保原始节点被改写为不同类型时hints 仍能被正确传播相关实现见 core/src/main/java/org/apache/calcite/rel/hint 包与RelOptRuleCall中的相关逻辑。2.4 接入 RelBuilder除 SQL 语法外1.22.0 还将 hints 引入RelBuilderCALCITE-3730并修复了RelHint缺少 Builder 的问题CALCITE-3766使得以编程方式构造关系表达式树时同样可以附加 hint。测试见 RelBuilderTest。三、Redis 适配器用 SQL 直查内存数据库Redis 是广泛使用的内存数据结构存储支持 string、hash、list、set、zset 等数据类型。Calcite 1.22.0 引入的 Redis 适配器让用户能够用 SQL 查询 Redis 中的实时数据并可与其他 Calcite schema 中的数据进行 JOIN从而将缓存层纳入统一查询体系。官方文档 site/_docs/redis_adapter.md 对该适配器做了完整说明源码位于 redis/src/main/java/org/apache/calcite/adapter/redis 目录。3.1 工作原理与支持的数据格式Redis 中没有表与列的概念每个 key-value 对在适配器中被视为一行。要把它拆分成可查询的列需要通过模型定义Model文件描述表结构。适配器当前支持三种数据格式由枚举RedisDataFormat定义格式说明raw保持 Redis key-value 原样仅暴露一个key列用于查询csv将 value 视为 CSV 文本按分隔符解析成多列默认分隔符为冒号:json将 value 视为 JSON 字符串按字段映射解析成多列官方文档指出 string、hash、set、zset、list 等 value 类型均受支持未来计划进一步支持 HyperLogLog 与 Pub/Sub。3.2 模型配置Schema 与 Table 两级工厂Redis 适配器遵循 Calcite 自定义 adapter 的标准模式schema 级与表级各有一个工厂类。Schema 级工厂RedisSchemaFactory负责创建RedisSchema其create()方法会校验并读取以下连接参数tables表定义列表必填hostRedis 主机地址必填port端口必填databaseRedis 逻辑库编号必填password密码可选为空则不需要认证。这些参数被封装进RedisConfighost/port/database/password 四个字段。表级工厂RedisTableFactory则负责创建RedisTable它会从 schema 中解析每个表的结构信息见RedisTableFieldInfotableName、dataFormat、fields、keyDelimiter其中keyDelimiter默认值为冒号。RedisTable实现了ScannableTablescan()方法通过RedisEnumerator按表名从 Redis 中拉取数据。3.3 完整模型示例以下是一个同时包含三种格式表的模型文件与仓库测试模型 redis/src/test/resources/redis-mix-model.json 结构一致也收录于官方文档{ version: 1.0, defaultSchema: foodmart, schemas: [ { type: custom, name: foodmart, factory: org.apache.calcite.adapter.redis.RedisSchemaFactory, operand: { host: localhost, port: 6379, database: 0, password: }, tables: [ { name: json_01, factory: org.apache.calcite.adapter.redis.RedisTableFactory, operand: { dataFormat: json, fields: [ { name: DEPTNO, type: varchar, mapping: DEPTNO }, { name: NAME, type: varchar, mapping: NAME } ] } }, { name: raw_01, factory: org.apache.calcite.adapter.redis.RedisTableFactory, operand: { dataFormat: raw, fields: [ { name: id, type: varchar, mapping: id }, { name: city, type: varchar, mapping: city }, { name: pop, type: int, mapping: pop } ] } }, { name: csv_01, factory: org.apache.calcite.adapter.redis.RedisTableFactory, operand: { dataFormat: csv, keyDelimiter: :, fields: [ { name: EMPNO, type: varchar, mapping: 0 }, { name: NAME, type: varchar, mapping: 1 } ] } } ] } ] }3.4 关键参数说明keyDelimiter仅对 CSV 格式生效用于切分 value 得到各列默认是冒号。mapping将 Redis 数据映射到逻辑列。由于 Redis 没有列概念映射方式随格式而异——CSV 格式使用数组下标如EMPNO映射到下标 0、NAME映射到下标 1JSON 与 raw 格式则使用字段名如mapping: DEPTNO。dataFormat指定数据格式支持csv、json、raw三种取值对应RedisDataFormat枚举。raw 格式保留原始 key-value仅以一个字段参与查询。3.5 三种格式的实际查询效果仓库测试数据通过 redis/src/test/resources/start.sh 启动 Redis 服务并加载用 redis/src/test/resources/stop.sh 停止服务。官方文档给出了可直接复现的示例raw 格式——value 原样呈现仅一个key列127.0.0.1:6379 LPUSH raw_02 book1 sqlline select * from raw_02; ------- | key | ------- | book2 | | book1 | -------JSON 格式——解析 JSON value 并按字段映射展开为多列127.0.0.1:6379 LPUSH json_02 {DEPTNO:10,NAME:Sales1} sqlline select * from json_02; ------------------ | DEPTNO | NAME | ------------------ | 20 | Sales2 | | 10 | Sales1 | ------------------CSV 格式——按分隔符默认冒号切分 value 映射为多列127.0.0.1:6379 LPUSH csv_02 10:Sales sqlline select * from csv_02; --------------- | DEPTNO | NAME | --------------- | 20 | Sales | | 10 | Sales | ---------------3.6 通过 sqlline 连接查询在构建好源码并启动 Redis 服务后可以直接使用 sqlline 以 JDBC 方式连接模型文件进行查询官方文档演示$ ./sqlline sqlline !connect jdbc:calcite:modelredis/src/test/resources/redis-mix-model.json admin admin sqlline !tables -------------------------------------------------------------------- | TABLE_CAT | TABLE_SCHEM | TABLE_NAME | TABLE_TYPE | REMARKS | ... | -------------------------------------------------------------------- | | foodmart | csv_01 | TABLE | | | | | foodmart | json_01 | TABLE | | | | | foodmart | raw_01 | TABLE | | | --------------------------------------------------------------------Redis 中的实时数据还可以与其他 schema 的表做 JOIN。官方文档展示的示例是 CSV 表与 JSON 表关联sqlline Select a.DEPTNO, b.NAME from csv_01 a left join json_02 b on a.DEPTNOb.DEPTNO; ------------------ | DEPTNO | NAME | ------------------ | 10 | Sales1 | ------------------该 JOIN 场景同样被仓库测试覆盖RedisAdapterCaseBase 中的testSqlWithJoin()使用CalciteAssert.model(model)对同一模型执行了完全相同的查询并断言结果DEPTNO10; NAMESales1。测试类还通过testRedisBySql()对raw_01、csv_01、json_01等 15 张表逐一执行count(*)验证行数。四、Oracle 与 MySQL 函数增强1.22.0 在函数层面继续向 Oracle/MySQL 等方言对齐。这些库函数统一注册在SqlLibraryOperators通过LibraryOperator(libraries {ORACLE})/LibraryOperator(libraries {MYSQL})注解按方言启用。4.1 Oracle XML 函数XMLTRANSFORMCALCITE-3579对 XML 字符串应用 XSLT 变换返回VARCHAREXTRACT(XML)CALCITE-3580从 XML 中提取匹配 XPath 的部分返回VARCHAREXISTSNODECALCITE-3640判断 XPath 节点是否存在。4.2 MySQL 数学函数CBRTCALCITE-3684立方根TANHCALCITE-3695双曲正切COSHCALCITE-3707双曲余弦同时支持带底数的LOG(numeric1, numeric2)MySQL 语义与LOG2。此外还有EXTRACTVALUEMySQLCALCITE-3552与一批 MySQL JSON 函数JSON_TYPE、JSON_DEPTH、JSON_LENGTH、JSON_KEYS、JSON_PRETTY、JSON_REMOVE、JSON_STORAGE_SIZE、JSON_INSERT、JSON_REPLACE、JSON_SET在 1.22.0 前后陆续补齐可从上述源码文件中逐一核对。五、关键 Bug 修复1.22.0 修复的四个代表性缺陷如下问题修复内容CALCITE-2018RelSet合并这一罕见场景下元数据缓存可能处于不一致状态本次修复了缓存一致性问题相关回归可见 RelMetadataTestCALCITE-1824GROUP_ID()返回错误结果。该函数无参数用于区分GROUP BY产生的重复分组若某分组有 n 个重复则返回 0 到 n-1。实现见 SqlGroupIdFunction语义与 Oracle 一致CALCITE-3711CORRELATE相关子查询关联节点此前estimateRowCount恒返回 1导致行数估计严重失真本次修复为正确估算CALCITE-3435DECIMAL类型执行MOD取模时精度推断不正确本次修复了结果类型的精度/标度推导六、兼容性与破坏性变更根据 site/_docs/history.md 的 1.22.0 章节该版本在 Linux、macOS、Microsoft Windows 上通过测试支持 Oracle JDK 813 与 OpenJDK 813Guava 版本 19.027.1-jre并针对 Apache Flink 1.10.0 做过验证其余软件版本以 gradle.properties 为准。对于基于 Calcite 做二次开发的用户1.22.0 引入了如下破坏性变更升级时需特别注意Project、TableScan、Calc、Aggregate、Join的构造函数新增hints参数CALCITE-482逻辑RelNode的create方法需要显式传入 hintsCALCITE-3723Project的列名不再体现在RelNodedigest 中CALCITE-3713RexCall默认在RelNodedigest 中规范化CALCITE-2450RelBuilder.aggregate会裁剪输入中未使用的字段可能导致计划发生变化CALCITE-3763RelBuilder.scan与 SQL 转 Rel 过程总是调用RelOptTable.toRel若toRel此前返回物理节点TableScan的计划可能变化。七、小结Apache Calcite 1.22.0 是一个能力增量显著的版本SQL Hints 打通了SQL 语法 →SqlHint→RelHint→HintStrategyTable→ 规划规则的完整链路为查询调优提供了标准化的表达方式Redis 适配器以 schema/table 两级工厂加三种数据格式的模型定义让 SQL 能直接查询内存中的实时数据并参与 JOINOracle XML、MySQL 数学与 JSON 函数进一步缩小了与主流数据库的语法差距。配合对GROUP_ID、CORRELATE行数估计、DECIMAL 取模精度等缺陷的修复该版本为后续 Calcite 的规划器与适配器生态奠定了坚实基础。读者可继续阅读 site/_docs/redis_adapter.md 与 site/_docs/history.md 获取更完整的历史演进与使用细节。赞分享后端数据库【免费下载链接】calciteApache Calcite项目地址https://gitcode.com/gh_mirrors/ca/calcite点击查看免费下载相关推荐Apache Calcite 1.42.0 发布全新去相关算法与 SQL 语法、函数、适配器增强详解Apache Calcite 1.42.0 发布全新去相关算法与 SQL 语法、函数、适配器增强详解 Apache Calcite 1.42.0 是该项目在后端数据库Apache Calcite扩展函数开发自定义SQL函数的实现方法Apache Calcite扩展函数开发自定义SQL函数的实现方法 Apache Calcite是一个强大的数据管理框架它提供了灵活的数据查询优化和SQL解后端数据库Apache Beam Calcite SQL 完全指南默认 SQL 方言的语法、数据类型、函数与扩展能力解析Apache Beam Calcite SQL 完全指南默认 SQL 方言的语法、数据类型、函数与扩展能力解析 本文以 Apache Beam 官方文档 Be批处理流处理大数据上一篇KubeOS安全实践如何利用dm-verity和安全启动保护rootfs完整性下一篇openEuler LLVM Flang编译器现代Fortran语言支持完全教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →