深度解析JQuick-SQL 逻辑计划到物理计划生成机制|分布式SQL原理

发布时间:2026/10/27 17:47:03
深度解析JQuick-SQL 逻辑计划到物理计划生成机制|分布式SQL原理

深度解析JQuick-SQL 逻辑计划到物理计划生成机制|分布式SQL原理

Meta 描述:本文基于jquick-sql架构原理解析JQuickPhysicalPlanGenerator如何把逻辑计划映射为可执行物理节点,涵盖Table Scan、Hash Join、Nested Loop Join、Hash Aggregate、Exchange与TopN,并说明Java分布式SQL引擎架构、SQL查询优化原理及gRPC分布式数据交换的衔接。

标签:jquick-sql架构原理、Physical Plan、JQuickPhysicalPlanGenerator、Hash Join、Hash Aggregate、gRPC分布式数据交换

官网示例:

  • FORMULAS 示例页:https://www.jquick.org/jquick-sql
  • github 地址:https://github.com/paohaijiao/jquick-sql

前言

逻辑计划回答“查询由哪些关系操作组成”,物理计划(Physical Plan)进一步回答“用哪些执行节点完成这些操作”。JQuick-SQL 中的JQuickPhysicalPlanGenerator负责这一映射;它接收JQuickLogicalPlanNode,生成对应的JQuickPhysicalPlanNode,然后调用物理优化器做进一步调整。

这一步是从 SQL查询优化原理走向执行实现的分界:逻辑层的 Join 不指定算法,物理层才选择 Hash Join 或 Nested Loop Join;逻辑层的 GroupBy 不指定交换方式,物理优化后才可能出现 Exchange 与两阶段聚合。

Generator入口与节点映射

生成入口为:

publicJQuickPhysicalPlanNodegenerate(JQuickLogicalPlanNodelogicalPlan){logicalPlan.accept(this);JQuickPhysicalPlanNodephysicalPlan=logicalToPhysical.get(logicalPlan);if(physicalPlan!=null){physicalPlan=optimizer.optimize(physicalPlan);}returnphysicalPlan;}

该实现先通过 Visitor 访问逻辑节点,再从映射表取得物理节点,最后执行JQuickPhysicalPlanOptimizer。已确认的映射包括:TableScan →JQuickTableScanPhysicalNode、Filter →JQuickFilterPhysicalNode、Project →JQuickProjectPhysicalNode、Sort →JQuickSortPhysicalNode、Limit →JQuickLimitPhysicalNode,以及 Values、Empty、Window、Set Operation、Recursive Union 等节点。

Join:算法选择不写死在SQL里

处理JQuickJoinNode时,生成器会检查连接类型与连接条件。CROSS JOIN 或满足等值连接条件的 Join 可以构造成JQuickHashJoinPhysicalNode;其构造参数包含 join type、左右 child、条件、join keys、build side、分布方式及别名。初始分布方式被设为SHUFFLE_HASH,后续物理优化器会根据统计信息调整。

其他条件走JQuickNestedLoopJoinPhysicalNode。因此,不应把“所有 JOIN 都是 Hash Join”当成项目事实:是否具备可提取的等值键会影响物理节点选择。

聚合、限制与物理优化

逻辑 GroupBy 会被转换为JQuickHashAggregatePhysicalNode,初始阶段为AggregateStage.SINGLE。之后物理优化器可能把大数据量且带 group keys 的聚合改写为 PARTIAL、SHUFFLE Exchange、FINAL 三段结构。

Limit 也不必保持原形。物理优化器发现JQuickLimitPhysicalNode的子节点为JQuickSortPhysicalNode时,会产生JQuickTopNPhysicalNode。这表明 Generator 负责忠实映射逻辑语义,而优化器负责组合节点层面的执行改写。

Exchange与计划边界

JQuickExchangePhysicalNode属于真实物理节点,保存 exchange type、partition strategy、partition keys、target parallelism 与 child。它继承 child 的输出 schema 与统计信息,本身不重新定义列结构。Exchange 为 Fragment 之间的数据再分布提供计划表示,是 Java分布式SQL引擎架构中连接本地算子和 gRPC 数据传输的关键桥梁。

Logical Join / GroupBy ↓ JQuickPhysicalPlanGenerator ↓ Physical Nodes ↓ JQuickPhysicalPlanOptimizer ↓ Hash Join分布调整 / TopN / Exchange / 两阶段聚合

实操代码案例

README 的嵌入式模式可以触发完整执行管线:

JQuickSQLsql=JQuickSQL.embedded();try{sql.registerTable("users",columns,rows);JQuickDataSetresult=sql.execute("SELECT id, name, age FROM users WHERE age >= 25 ORDER BY age DESC");result.printTable();}finally{sql.shutdown();}

该示例不直接暴露物理节点,但在内部链路中,扫描、过滤、投影、排序与执行均需经过计划生成。文档中的embedded()与shutdown()均为 README 已提供的真实接口。

常见问题

Physical Plan是否等于最终分布式任务?

不完全等于。物理计划之后还会经过 Fragmenter 切分,形成可调度的 Fragment。

为什么生成器后还要优化?

生成器完成逻辑到物理的基础映射;物理优化器再进行 Join 分布选择、两阶段聚合、TopN 与 Exchange 等改写。

Exchange会改变结果字段吗?

JQuickExchangePhysicalNode的输出 schema 直接继承 child,重点是数据分发而不是列转换。

总结与拓展

JQuickPhysicalPlanGenerator把逻辑语义落到实际执行节点,并把节点树交给物理优化器。其价值在于将 Scan、Filter、Project、Join、Aggregate、Sort、Limit 等操作落实为可执行结构,同时为 Exchange 与 Fragment 分布式调度留下明确接口。

Core Advantage

It separates logical semantics from executable algorithms and distribution decisions.

Applicable Scenarios

Physical-plan debugging, execution tuning, distributed planning, and operator development.