您当前的位置:首页 > 电脑百科 > 数据库 > 百科

使用 Calcite 解析 SQL 获取源表和结果表

时间:2022-08-30 14:31:06  来源:今日头条  作者:SapphireCoder

导读:本文将讨论关于使用 Calcite 解析单条 SQL 获取源表和结果表的思路。

实现思路

Apache Calcite是一款开源的动态数据管理框架,它提供了标准的SQL语言、多种查询优化和连接各种数据源的能力,但不包括数据存储、处理数据的算法和存储元数据的存储库。

 

我们可以借助 Calcite SqlParser 解析器分析 SQL 并生成 AST 语法树,并通过访问 AST 的各个节点获取到我们想要的信息。

具体实现

构建 Calcite SqlParser 解析器解析 SQL 并生成 AST 语法树

 @Test
    void test() {
        String sql = "insert into ... select ...";
        // 在解析前可以对 SQL 语句进行预处理,比如将不支持的 && 替换为 AND, != 替换为 <>
        SqlParser.Config config =
                SqlParser.configBuilder()
                        .setParserFactory(FlinkSqlParserImpl.FACTORY)
                        .setLex(Lex.JAVA)
                        .setIdentifierMaxLength(256)
                        .build();
        // 创建解析器
        SqlParser sqlParser = SqlParser
                .create(sql, config);
        // 生成 AST 语法树
        SqlNode sqlNode;
        try {
            sqlNode = sqlParser.parseStmt();
        } catch (SqlParseException e) {
            throw new RuntimeException("使用 Calcite 进行语法分析发生了异常", e);
        }
      	SqlBloodRes res = new SqlBloodRes();
        // 递归遍历语法树
        getDependencies(sqlNode, res, false);
    }

此处笔者参考了 从 SQL 语句中解析出源表和结果表 - JR's Blog 所提供的思路。在 Calcite 解析出来的 AST 是以 SqlNode 的形式表现的,一个 SqlNode 即是 AST 中的一个节点。SqlNode 有许多类型,我们关注的 Source 和 Sink 表表名在 AST 中会是一个 SqlIdentifier 的叶子结点。(注意:并非所有 SqlIdentifier 叶子结点都对应表名,列名也对应 SqlIdentifier)

在一条 SQL 中,最终出现表的引用的情况归结于以下两种情况:

  • SELECT 语句的 FROM clause 中的直接引用
  • JOIN 语句中 LEFT 和 RIGHT clause 中的直接引用

嵌套子查询的 SQL 语句中,最终进入到子查询的 AST 子树中,只要出现了对表的引用,一定会分解出以上两种结构。因此,对于一个 SqlIdentifier 类型的叶子节点,在以下两种情况下,该叶子结点就是一个表的引用:

  • 父节点是 SqlSelect,且当前节点是父节点的 FROM 子句派生出的子节点
  • 父节点是 SqlJoin(如果是 Lookup join 则节点为 SNAPSHOT 类型,需继续深入子节点)

另外,一种特殊的情况需要加以考虑。在 SQL 中 AS 常用作起别名,因而可能 SqlIdentifier 的父节点是 AS,而 AS 的父节点是 SELECT 或 JOIN。这种情况下,我们可以将 AS 看作一种 “转发” 结点,即 AS 的父节点和子节点忽略掉 AS 结点,直接构成父子关系。

从根结点开始遍历 AST,解析所有的子查询,找到符合上述两种情况的子结构,就可以提取出所有对表的引用。

private SqlBloodRes getDependencies(SqlNode sqlNode, SqlBloodRes res, Boolean fromOrJoin) {
        if (sqlNode.getKind() == JOIN) {
            SqlJoin sqlKind = (SqlJoin) sqlNode;
            getDependencies(sqlKind.getLeft(), res, true);
            getDependencies(sqlKind.getRight(), res, true);
        } else if (sqlNode.getKind() == IDENTIFIER) {
            if (fromOrJoin) {
                // 获取 source 表名
                res.getSourceTables().put(sqlNode.toString(), sqlNode.toString());
            }
        } else if (sqlNode.getKind() == AS) {
            SqlBasicCall sqlKind = (SqlBasicCall) sqlNode;
            if (sqlKind.getOperandList().size() >= 2) {
                getDependencies(sqlKind.getOperandList().get(0), res, fromOrJoin);
            }
        } else if (sqlNode.getKind() == INSERT) {
            SqlInsert sqlKind = (SqlInsert) sqlNode;
            // 获取 sink 表名
            res.setSinkTable(sqlKind.getTargetTable().toString());
            getDependencies(sqlKind.getSource(), res, false);
        } else if (sqlNode.getKind() == SELECT) {
            SqlSelect sqlKind = (SqlSelect) sqlNode;
            List<SqlNode> list = sqlKind.getSelectList().getList();
            for (SqlNode i : list) {
                getDependencies(i, res, false);
            }
            getDependencies(sqlKind.getFrom(), res, true);
        } else if (sqlNode.getKind() == SNAPSHOT) {
            // 处理 Lookup join 的情况
            SqlSnapshot sqlKind = (SqlSnapshot) sqlNode;
            getDependencies(sqlKind.getTableRef(), res, true);
        }   else {
            // TODO 这里可根据需求拓展处理其他类型的 sqlNode
        }
        return res;
    }

结果封装

@Data
public class SqlBloodRes {

    private Map<String, String> sourceTables = new HashMap<>();

    private String sinkTable;
}

最后

上面就是使用 Calcite 解析 SQL 获取源表和结果表的思路,Demo 实现比较粗糙,各位可以根据实际场景及自身需求进行优化丰富。



Tags:Calcite   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Apache Calcite: 初窥门径
概述Apache Calcite的前身是optiq,是Hive中做CBO(Cost Based Optimization, 基于成本的优化)的一个模块。2014年5月从Hive项目中独立出来,成为Apache社区的孵化项目,同年9月正...【详细内容】
2022-10-05  Search: Calcite  点击:(515)  评论:(0)  加入收藏
使用 Calcite 解析 SQL 获取源表和结果表
导读:本文将讨论关于使用 Calcite 解析单条 SQL 获取源表和结果表的思路。实现思路Apache Calcite是一款开源的动态数据管理框架,它提供了标准的SQL语言、多种查询优化和连接...【详细内容】
2022-08-30  Search: Calcite  点击:(990)  评论:(0)  加入收藏
使用Apache Calcite解析数据库查询
Knoldus Inc.3分钟阅读嘿那里,作为一个技术人员有时我们必须编写数据库的查询,看起来不错,但我们不知道我们写的查询是句法正确的。所以在这个博客中,我们在Apache Calcite的帮...【详细内容】
2021-02-24  Search: Calcite  点击:(1115)  评论:(0)  加入收藏
▌简易百科推荐
向量数据库落地实践
本文基于京东内部向量数据库vearch进行实践。Vearch 是对大规模深度学习向量进行高性能相似搜索的弹性分布式系统。详见: https://github.com/vearch/zh_docs/blob/v3.3.X/do...【详细内容】
2024-04-03  京东云开发者    Tags:向量数据库   点击:(5)  评论:(0)  加入收藏
原来 SQL 函数是可以内联的!
介绍在某些情况下,SQL 函数(即指定LANGUAGE SQL)会将其函数体内联到调用它的查询中,而不是直接调用。这可以带来显著的性能提升,因为函数体可以暴露给调用查询的规划器,从而规划器...【详细内容】
2024-04-03  红石PG  微信公众号  Tags:SQL 函数   点击:(5)  评论:(0)  加入收藏
如何正确选择NoSQL数据库
译者 | 陈峻审校 | 重楼Allied Market Research最近发布的一份报告指出,业界对于NoSQL数据库的需求正在持续上升。2022年,全球NoSQL市场的销售额已达73亿美元,预计到2032年将达...【详细内容】
2024-03-28    51CTO  Tags:NoSQL   点击:(14)  评论:(0)  加入收藏
为什么数据库连接池不采用 IO 多路复用?
这是一个非常好的问题。IO多路复用被视为是非常好的性能助力器。但是一般我们在使用DB时,还是经常性采用c3p0,tomcat connection pool等技术来与DB连接,哪怕整个程序已经变成以...【详细内容】
2024-03-27  dbaplus社群    Tags:数据库连接池   点击:(14)  评论:(0)  加入收藏
八个常见的数据可视化错误以及如何避免它们
在当今以数据驱动为主导的世界里,清晰且具有洞察力的数据可视化至关重要。然而,在创建数据可视化时很容易犯错误,这可能导致对数据的错误解读。本文将探讨一些常见的糟糕数据可...【详细内容】
2024-03-26  DeepHub IMBA  微信公众号  Tags:数据可视化   点击:(7)  评论:(0)  加入收藏
到底有没有必要分库分表,如何考量的
关于是否需要进行分库分表,可以根据以下考量因素来决定: 数据量和负载:如果数据量巨大且负载压力较大,单一库单一表可能无法满足性能需求,考虑分库分表。 数据增长:预估数据增长...【详细内容】
2024-03-20  码上遇见你  微信公众号  Tags:分库分表   点击:(15)  评论:(0)  加入收藏
在 SQL 中写了 in 和 not in,技术总监说要炒了我……
WHY?IN 和 NOT IN 是比较常用的关键字,为什么要尽量避免呢?1、效率低项目中遇到这么个情况:t1表 和 t2表 都是150w条数据,600M的样子,都不算大。但是这样一句查询 &darr;select *...【详细内容】
2024-03-18  dbaplus社群    Tags:SQL   点击:(6)  评论:(0)  加入收藏
应对慢SQL的致胜法宝:7大实例剖析+优化原则
大促备战,最大的隐患项之一就是慢SQL,对于服务平稳运行带来的破坏性最大,也是日常工作中经常带来整个应用抖动的最大隐患,在日常开发中如何避免出现慢SQL,出现了慢SQL应该按照什...【详细内容】
2024-03-14  京东云开发者    Tags:慢SQL   点击:(5)  评论:(0)  加入收藏
过去一年,我看到了数据库领域的十大发展趋势
作者 | 朱洁策划 | 李冬梅过去一年,行业信心跌至冰点2022 年中,红衫的一篇《适应与忍耐》的报告,对公司经营提出了预警,让各个公司保持现金流,重整团队,想办法增加盈利。这篇报告...【详细内容】
2024-03-12    InfoQ  Tags:数据库   点击:(32)  评论:(0)  加入收藏
SQL优化的七个方法,你会哪个?
一、插入数据优化 普通插入:在平时我们执行insert语句的时候,可能都是一条一条数据插入进去的,就像下面这样。INSERT INTO `department` VALUES(1, &#39;研发部(RD)&#39;, &#39...【详细内容】
2024-03-07  程序员恰恰  微信公众号  Tags:SQL优化   点击:(20)  评论:(0)  加入收藏
站内最新
站内热门
站内头条