乐趣区

关于sql:Databend-SQL-Planner-全新设计

前言

为了反对简单的 SQL 查问,并且提供更好的应用体验,咱们在最近的几个月里对 Databend 的 SQL planner 进行了大规模的重构。目前重构曾经靠近序幕,感兴趣的敌人能够通过批改 Databend 的 Session settings

SET enable_planner_v2 = 1

来启用新 planner 进行领先体验。

性能亮点

更加敌对的查问体验

无论是数据分析师还是开发人员,在编写 SQL 查问的时候总会遇到各种各样的报错。尤其是在 SQL 查问较为简单的状况下,排查报错成了许多人的噩梦(笔者自己已经批改过有数十个 JOIN 子句的 MySQL 查问,从此对 MySQL 的谬误提醒疾恶如仇)。

为了改善这方面的用户体验,咱们在新的 Planner 中引入了严格的语义查看环节,使得大部分的谬误能够在查问编译阶段就被拦挡。同时为了不便用户定位谬误的地位,咱们也引入了全新的谬误提醒算法。

当你的 SQL 查问应用了谬误的语法时(比方写错了关键字,或者脱漏了某些子句),Databend 会为你提供提示信息:

当你的 SQL 查问呈现语义上的谬误时(比方应用了不存在的 Column,或者 Column 具备歧义),Databend 也会为你指出谬误呈现的地位:

在编写简单查问时,仍然能够取得较好的体验:

反对 JOIN 查问与关联子查问

在新的 SQL planner 中,咱们反对了 JOIN 查问(INNER JOIN,OUTER JOIN,CROSS JOIN)与关联子查问,并且提供了 Hash Join 算法用以执行 JOIN 查问。

JOIN 查问的相干文档曾经公布在 https://databend.rs/doc/refer…,你能够查阅文档以理解 Databend 中 JOIN 查问的应用形式。

在 OLAP 查问中,JOIN 是十分重要的一部分。在传统的 星型模型 雪花模型 中,咱们都须要通过 JOIN 查问将 维度表 事实表 连接起来以生成后果报表。

TPCH Benchmark 是由 TPC 委员会制订的一套 OLAP 查问基准测试规范,用于评测数据库系统的 OLAP 能力。其中蕴含了 8 张表,别离是:

  • Lineitem:产品我的项目
  • Orders:订单信息
  • Customer:顾客信息
  • Part:零部件信息
  • Supplier:供应商信息
  • Partsupp:整机与供应商的关系表
  • Nation:国家信息
  • Region:地区信息

TPCH 中有 22 条简单的查问,对应不同的商业需要。这里以 Q9 查问为例,它的用处是计算指定 年度 地区 利润额,其中蕴含了大量的 JOIN 计算。在新的 Planner 中,咱们曾经能够反对该查问:

关联子查问同样也是 SQL 中的重要组成部分,通过关联子查问能够轻松示意简单的查问逻辑。TPCH 的 Q4 就是一个例子,它的用处是计算一段时间内 各优先级 的订单的 交付状况 。其中应用了 EXISTS 关联子查问来筛选 逾期收货 的订单:

目前 Databend 仅反对了关联子查问的简略执行,相干的查问优化工作仍在进行中,敬请期待。

全新架构

新的 SQL planner 中咱们对 SQL 解析的流程进行了从新设计,以撑持更加简单的语义剖析和 SQL 优化。在新的 SQL planner 中,一条 SQL 语句通过客户端发送到 databend-query server 后,会依照下图所示的程序由不同的组件进行解决,最终将查问的后果返回给客户端:

收到 SQL 查问后,Parser 组件会对其进行解析。在此步骤中如果遇到了语法错误则会间接将错误信息返回给客户端,解析胜利则会生成查问对应的 AST(形象语法树)。

Parser

为了提供更丰盛的语法分析性能和更好的开发体验,咱们开发了一套基于 nom Parser combinator 的 DSL (畛域特定语言) nom-rule,并基于该框架从新编写了 SQL Parser。

在这套框架下咱们能够十分轻松地定义一条 Statement 的语法,以 CREATE TABLE 语句为例,咱们能够应用 DSL 将其简略形容为:

CREATE ~ TABLE ~ #identifier ~ "(" ~ (#column_def)+ ~ ")" ~ ";"

优雅的语法大大提高了编写 Parser 的乐趣,欢送有趣味的敌人们进行尝试。

Binder

由 Parser 胜利解析出 AST 后,咱们会通过 Binder 对其进行语义剖析,并且生成一个初始的 Logical Plan(逻辑打算)。在此过程中,咱们会进行不同类型的语义剖析:

  • Name resolution:通过查问 Databend Catalog 中相干的 Table, Column 对象信息,来查看 SQL 查问中援用的变量的合法性。并将非法的变量与对应的对象进行绑定,以进行后续的剖析。
  • Type check:依据 name resolution 中拿到的信息,对表达式的合法性进行查看,并且为表达式寻找适合的返回类型。
  • Subquery unnesting:将表达式中的子查问提取进去,翻译成关系代数的模式
  • Grouping check: 对于含有聚合计算的查问,剖析是否在聚合函数以外援用了非聚合列

通过语义剖析,咱们能够排除掉绝大多数的语义谬误,并在编译阶段将其返回给用户,以提供最佳的谬误排查体验。

Optimizer

失去初始的 Logical Plan 后,优化器会对其进行改写和优化,最终生成一个可执行的 Physical Plan。

在新的 Planner 中,咱们引入了一套基于 Transformation Rule 的优化器框架(Volcano/Cascades)。通过定义一个关系代数子树结构的 Pattern 以及相干的 Transform 逻辑,即可实现一个独立的 Rule。

以简略的 Predicate Push Down 为例:

咱们只须要定义输出的 Plan 的 Pattern:

impl RulePushDownFilterProject {pub fn new() -> Self {
        Self {
            id: RuleID::PushDownFilterProject,
            // Filter
            //  \
            //   Project
            //    \
            //     *
            pattern: SExpr::create_unary(
                Pattern {plan_type: RelOp::Filter,},
                SExpr::create_unary(
                    Pattern {plan_type: RelOp::Project,},
                    SExpr::create_leaf(
                        Pattern {plan_type: RelOp::Pattern,},
                    ),
                ),
            ),
        }
    }
}

并且实现一个进行转换的函数:

impl RulePushDownFilterProject {pub fn apply(&self, s_expr: SExpr) -> Result<SExpr> {let filter = s_expr.plan().into();
        let project = s_expr.child(0).plan().into();
        let result = SExpr::create_unary(
            project, 
            SExpr::create_unary(
                filter,
                s_expr.child(0).child(0)
            )
        );
        
        Ok(result)
    }
}

Interpreter

通过 Optimizer 生成 Physical Plan 后,咱们会将其翻译成可执行的 Pipeline,并交由 Databend 的 Processor 执行框架进行计算。至此 Planner 的工作就告一段落,置信读者也对新 Planner 的架构有了一个初步的理解。更多的技术细节请关注咱们的后续文章。

将来布局

从头构建一个 SQL Planner 是一件非常具备挑战性的事件,然而通过从新的设计和开发,咱们能够找到最适宜零碎自身的架构与性能。在将来的一段时间里,咱们将继续欠缺和坚固新的 SQL Planner,性能方面则会重视于:

  • Cost-based Optimization(CBO, 基于代价的优化)
  • 分布式查问优化
  • 更多的优化规定

目前,新的 SQL planner 的迁徙工作曾经靠近序幕,你能够通过该 issue 追踪进度。预计在七月份内所有的迁徙工作将会实现,届时咱们将会公布版本更新的布告,敬请期待。

对于 Databend

Databend 是一款开源、弹性、低成本,基于对象存储也能够做实时剖析的旧式数仓。期待您的关注,一起摸索云原生数仓解决方案,打造新一代开源 Data Cloud。

  • Databend 文档:https://databend.rs/
  • Twitter:https://twitter.com/Datafuse_…
  • Slack:https://datafusecloud.slack.com/
  • Wechat:Databend
  • GitHub:https://github.com/datafusela…


文章首发于公众号:Databend

退出移动版