SQL Compiler:智能生成、优化各类数据库查询SQL

Agile Query 中的 SQL 编译器

Agile Query 的 SQL 编译器在架构上与标准编译器相似,但其核心差异在于它们编译的目标不同。传统编译器负责将源代码转换成操作系统或 CPU 架构能够识别的指令 (例如,机器代码或 LLVM 的中间表示,再由 LLVM 编译器统一处理),然后由操作系统和 CPU 直接执行,或者对于某些动态语言,由运行时环境进行解释和执行。相比之下, Agile Query 的 SQL 编译器将源代码直接编译成数据库能够直接解释和执行的 SQL 代码。

传统编译器需要适配不同 CPU 架构的指令集,而 Agile Query 的编译器则需适配不同数据库的 SQL 语法以及各自的执行引擎优化规则,以确保生成的 SQL 能在目标数据库中高效运行。 下图是 Agile Query 编译器的内部结构和处理过程:

  • 词法解析、语法解析是编译器的基础过程,与传统编译器类似,负责将文本文件解析为 AST(抽象语法树)。在此基础上,语义解析则进一步为 AST 实例填充状态,赋予其特定的行为和逻辑。
  • 标准函数库包含数据库提供的常用函数,如聚合函数和标量处理函数,而高级函数库则由 Agile Query 提供,封装了与领域更贴合的功能,以及对不同数据库函数语法的适配。
  • 中间代码生成相当于传统编译器中的 IR(中间表示)。大多数传统编译器采用 DAG(有向无环图)存储状态,Agile Query 也使用树形结构存储状态信息。这些状态包括投影、过滤、排序等关键操作。
  • 目标代码生成阶段是一个复杂的逻辑处理过程。此阶段,编译器解析查询所涉及的表,依据关系代数的计算规则拆分子查询,并最终将所有子查询图合并,构造出完整的查询逻辑。

Agile Query 编译器的目标是简化标准 SQL 的底层复杂逻辑。正如高级编程语言的发展历程,每一代新语言的出现都在降低编程的技能门槛,让开发者能够摆脱对底层技术细节的过度依赖, 专注于解决领域内的问题。在一些业务系统的 SQL 编程,除了各类统计指标的开发,开发者还需要面对下列技术细节:

  • 多对多关联分析:多对多场景在领域实体关系中非常常见,例如:客户与订单的关系、商品与品类的关系。当这些表在进行关联分析时,常常会遇到过度计算(over-counting 或 double-counting) 的问题(例如:统计每个客户购买的商品数据或品类数量)。为了解决这些问题,通常需要数据工程师通过优化 SQL 结构进行手动调整。
  • 子查询:在实际数据分析工作中,嵌套聚合、统计维度对齐等查询需求都需要子查,然而,目前主流的 ORM 框架通常不支持生成包含子查询的 SQL。如果尝试通过预计算来替代子查询, 不仅实现复杂度增加,开发成本也往往远高于直接编写子查询。

上述问题是数据分析工程中最为常见的问题,也是数据分析工作始终离不开数据工程师和程序员的重要原因。随着数据分析需求的不断变化,数据工程师的日常工作变得越来越重复且繁琐。 一个看似普通的数据分析需求往往需要多个部门协同完成,流程冗长,效率低下。数据工程师不仅需要负责数据的清洗与治理,还要应对各部门的各种数据分析需求。这种情况导致数据团队规模日益庞大, 使得数据分析这一常见且刚需的业务需求成本高昂,使用门槛也随之提高。

Agile Query 正是在这样的背景下应运而生。通过算法和规则自动生成查询 SQL,它显著提升了数据分析需求的开发效率。数据工程师只需专注于单个指标的计算逻辑, 而无需处理指标与其他维度或指标间的关联查询(由数据分析师或运营人员自由组合)。这不仅大幅减少了数据工程师的开发工作量,也加快了数据分析师和运营人员获取分析结果的速度, 大幅提升整体效率。

数据分析需求分类

在生成 SQL 之前,Agile Query 首先对数据分析需求的方式或模式进行分类,力求覆盖所有可能的数据分析需求。随后,根据不同的数据分析方法设计相应的 SQL 生成逻辑。 这正是上文中目标代码生成的核心设计理念。其中最关键的步骤是针对查询的合并,这是手工编写 SQL 时最容易被忽视的部分。Agile Query 通过分析数据分析需求涉及的表, 识别并合并可整合的查询逻辑,从而减少数据库从磁盘加载的数据量。这不仅优化了资源使用,还大幅提升了整体查询效率。Agile Query 对数据分析需求分为八个大类:

  • 简单聚合:例如:
    AVG(Price)
    SUM(Revenue)
    COUNT_DISTINCT(Users)
    、这些聚合指标通常以指标卡片的形式出现
  • 聚合值的算术运算:例如,利润可以定义为
    SUM(Revenue) - SUM(Cost) - SUM(Commissions)
    。或者,客单价可以定义为:
    SUM(Sales) / COUNT(Orders)
  • 需要 JOIN 的聚合:例如:计算不同品类的销售额可以定义为:
    SUM_IF(Product = '牛奶', Sales)
    ,Product 和 Sales 分别在品类表和订单表中, 当计算上述指标时,需要 JOIN 操作,典型场景:同时计算每个月牛奶、咖啡的销售额
  • 窗口函数的指标:例如:移动平均(Moving Averages),累计(Cumulative Sum),典型场景:计算一年内每月利润的累计值,能够体现出随时间变化,每个月利润的结余
  • 嵌套聚合:例如:月均销售额,月均利润,内层聚合需要
    SUM(Sales, TO_MONTH(Sales Date))
    ,外层聚合为
    AVG
    ,完整的形式为:
    AVG(SUM(Sales, TO_MONTH(Sales Date)))
  • 多维度聚合:典型场景:计算每个品类的销售额和客户数据,这类查询属于比较复杂的查询,因为品类表和客户表之间为多对多的关联关系,一个客户可以购买多个品类, 一个品类也可以被多个客户购买
  • 跨维度计算:典型场景:同时计算每个商品的销售额占总体销售的比例和占每个品类的比例,这类查询通常需要多个不同层级的维度对销售额进行聚合, 然后将多个聚合值拉平为同一维度,再进行算术运算
  • 分类或标签:当分析对象数量众多时,很难以单个实体的形式进行数据分析,例如:客户维度的分析,当客户数据很少时,可以以客户的维度进行分析,但当客户数据有几万、十几万时, 就很难以单个客户的维度进行分析,通常会以某种方式对客户进行分类,例如:将单位时间范围内的销售额切分为多个区间,以销售额区间的形式进行客户数据的分析。
  • 时间序列对比:时间序列对比在大都数行业的数据分析中者至关重要,例如:销售额的同环比或自由时间区间的对比,或者再结合其它维度的指标增长率等。

上述方法需求覆盖了大部分的数据分析需求,Agile Query 针对上述分析需求提供了不同的函数进行处理,标准聚合提供了与标准 SQL 同名的函数,但实际的聚合逻辑完全不同, 为非标准聚合提供了高级分析函数,例如:分类或标签的函数为

SEGMENT
函数。

与其它产品的比较

ChatBI(LLM 生成 SQL)

当前主流的 ChatBI 产品通常依赖于大语言模型(LLM)生成 SQL。根据不同的领域模型架构,这些产品将领域内的指标定义拆解为多个 SQL 片段,并依据用户的提问将这些片段拼接成完整的 SQL 查询,以执行后输出结果。然而,这种方法存在以下几个主要问题:

  • SQL 片段的构建:这本身就是一个复杂的过程,不仅需要应对模型结构的变化,还要将指标的计算逻辑转化为 SQL 查询。此外,由于大语言模型(LLM)生成 SQL 存在一定的不确定性, 这使得无法完全依赖模型自动生成的结果,仍然需要数据工程师进行二次验证和校对,使得整个数据分析过程变得极不稳定。
  • 时间性:目前,大语言模型的生成过程通常以秒为单位计算(过程复杂的可能为10 几秒)。然而,现代 MPP 型数据库的计算性能已经显著提升,大多数查询都能在亚秒级内完成。 如果在分析过程中需要频繁调整过滤条件、排序规则或新增指标,模型生成的延迟将极大拖慢整体效率,使数据分析变得冗长而低效。
  • 实施和维护成本:大语言模型在进行行业落地时,通用的行业知识和自身的知识出现冲突时,需要大量的行业知识作为输入,不仅需要构建 SQL 版本,同时还要匹配大量的文字性描述, 否则后期进行问题理解时,很容易出现指标计算逻辑错误。

本质上,大语言模型可以让熟练的人提升工作效率,但不能让完全不懂的人掌握一项技能,大语言模型模型可以让数据工程师提升写 SQL 的效率,但不能帮助数据分析师或运营人员, 快速获得数据分析结果。在不远的未来,Agile Query 也会集成大语言模型,但不是让它生成 SQL,也不会让它生成 Agile Query 内部的查询语言,而是让它做简单的语义匹配, 让大语言模型做的事越简单,出错的概率就越低,产品的可用性就越强。

而 Agile Query 是依靠算法和规则生成 SQL,可以 100% 确保生成 SQL 的准确率,指标定义为内部的 Flatql 语言,屏蔽了大量 SQL 编程中的技术细节,当模型结构发生变化, 只需要调整模型关系,而不需要调整指标定义。针对简单查询,Agile Query 生成 SQL 的时间低于 1 毫秒,复杂查询的时间成本在 1-2 毫秒之间,这样的时间成本完全可以忽略不计。

Tableau 和 PowerBI

Tableau 和 PowerBI 属于同类型数据分析工具,技术实现的原理也比较接近,都需要将数据从外部回到到内部,然后依靠内部的计算引擎进行复杂计算,再进行可视化处理, 这样也会导致超大数据量计算时,两者的计算效率不高。而 Agile Query 和 ThoughtSpot 一样,所有的计算都在数据库侧完成, 这样的技术实现方式对数据库的计算引擎依赖程度会非常高,但这样的技术实现原理的应用场景也会非常广泛,当数据量不是特别大时,可以避免数据迁移。

Tableau 和 PowerBI 的内部计算引擎与 Agile Query 的 SQL 编译技术在架构上有一定相似性,但在函数库的侧重点上有所不同。Agile Query 的函数库更专注于复杂的聚合计算, 而 PowerBI 更擅长标量计算和逻辑处理,Tableau 则聚焦于数据可视化的灵活性和表现力。尽管如此,Agile Query 目前在某些特定领域与这两者仍存在一定差距。 例如,在处理复杂计算需求时,PowerBI 更具优势;而在定义和实现数据可视化方面,Tableau 的能力更加突出。

国内 BI

目前,国内的主流 BI 工具更多关注于数据可视化,其核心功能集中在图表的生成与交互上,但在数据计算方面则较为依赖数据工程师的人工参与,通常需要预先计算好数据结果, 或者直接编写 SQL 查询以满足分析需求。这种模式不仅增加了数据工程师的工作负担,也使得分析需求的响应速度受到限制。

相比之下,Agile Query 在数据计算方面处于领先地位。通过其强大的 SQL 编译器和函数库,Agile Query 能够自动生成复杂的查询逻辑,无需工程师手动编写 SQL 或进行繁琐的预计算, 从而大幅提升了数据分析的效率和灵活性。

总结

随着MPP 型数据库的快速发展,大数据量的计算方法逐渐向SQL 这个古老的语言倾斜,数据加工层可以变得很薄且抽象程度也可以很高,个性化查询需求变得容易实现。 但SQL 的编程属性比较弱,工程化实施变得复杂,整个行业可能会往两个方向发展,一个就是类似 ObjectiveSql 这类项目, 提供一个可编程的SQL 框架,另一个方向就是设计一个更高级的分析语言,屏蔽一些关系计算的底层逻辑,让数据工程师或分析师将注意力聚焦在自身业务上, Agile Query 便是第二种方案,底层由FlatQL 编译器结合关系描述,将查询语言编译成SQL Dialect,并基于数据统计方法,设计了一系列高级聚合函数, 对外屏蔽了SQL 底层的关系计算逻辑。

全天候售后服务
7x24小时专业工程师品质服务
极速服务应答
秒级应答为业务保驾护航
客户价值为先
从服务价值到创造客户价值
全方位安全保障
私有化部署,充分保证数据安全
©2022-2025 上海磊数信息技术有限公司
沪ICP备2024066390号-1