前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何使用calcite构建SQL并执行查询

如何使用calcite构建SQL并执行查询

作者头像
麒思妙想
发布2023-08-28 15:37:24
5530
发布2023-08-28 15:37:24
举报
文章被收录于专栏:麒思妙想麒思妙想

大家好,这是 Calcite 的第二篇文章了,我一直毫不掩饰对她的喜爱,而且一直在致力于为社区做一些贡献,如果你也喜欢这个项目的话,欢迎评论,转发,如果没看过第一篇的话,也欢迎移步去看看(手把手教你使用Calcite查看SQL执行计划)。如果你还不了解这个项目的话,我也希望能通过我,让你知道这个优秀的项目。

今天我要分享的主题是关于 Calcite 关系代数 以及 SQL 的那些事,Let's go !!!

关系代数

首先关系代数是 Calcite 的核心。每个查询都可以表示为一个 关系运算符树。你可以将 SQL 转换为关系代数,也可以直接构建关系运算符树。

优化器规则使用保持 相同语义 的 数学恒等式 来变换表达式树。例如,如果过滤器没有引用其他输入中的列,那么将过滤器推入到内部关联的输入则是有效的。

Calcite 通过反复地将优化器规则应用于关系表达式来优化查询。成本模型指导该过程,优化器引擎生成与原始语义相同,但成本较低的替代表达式。

优化过程是可扩展的。你可以添加自己的 关系运算符、优化器规则、成本模型 和 统计信息。

代数构建器

构建关系表达式的最简单方法是使用代数构建器 RelBuilder。下面是一个例子:

扫描表

代码语言:javascript
复制
FrameworkConfig config;
RelBuilder builder = RelBuilder.create(config);
RelNode cnode = relBuilder.scan("consumers").build();
System.out.println("==> "+RelOptUtil.toString(cnode));

其执行结果如下:

代码语言:javascript
复制
==> LogicalTableScan(table=[[consumers]])

等价与SQL

代码语言:javascript
复制
SELECT * FROM consumers ;

添加投影

现在,让我们添加一个投影,相当于如下 SQL:

代码语言:javascript
复制
SELECT firstname,lastname FROM consumers ;

我们只需要在调用 build 方法前,添加一个 project 方法调用:

代码语言:javascript
复制
cnode = relBuilder.scan("consumers").project(relBuilder.field("firstname"),
        relBuilder.field("lastname")).build();
System.out.println("==> "+RelOptUtil.toString(cnode));

其执行结果如下:

代码语言:javascript
复制
==> LogicalProject(firstname=[$1], lastname=[$2])
  LogicalTableScan(table=[[consumers]])

添加过滤聚合

下面是一个包含聚合和过滤的查询语句:

代码语言:javascript
复制
cnode = relBuilder.scan("orders")
            .aggregate(
                    relBuilder.groupKey("goods"),
                    relBuilder.count(false, "c"),
                    relBuilder.sum(false, "p", relBuilder.field("price")))
            .filter(
                    relBuilder.call(
                        SqlStdOperatorTable.GREATER_THAN,
                                relBuilder.field("c"),
                                relBuilder.literal(1))
                    ).build();

System.out.println(RelOptUtil.toString(cnode));

相当于如下 SQL:

代码语言:javascript
复制
SELECT goods, count(*) AS count, sum(price) AS p FROM orders GROUP BY goods HAVING count(*) > 1

其执行结果如下:

代码语言:javascript
复制
LogicalFilter(condition=[>($1, 1)])
  LogicalAggregate(group=[{1}], c=[COUNT()], p=[SUM($2)])
    LogicalTableScan(table=[[orders]])

好了,接下来我们来看进一步的实例。

实例 CalciteRelBuilderCase 完整代码

代码语言:javascript
复制
package com.dafei1288;

import org.apache.calcite.adapter.csv.CsvSchema;
import org.apache.calcite.adapter.csv.CsvTable;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.JoinRelType;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.tools.FrameworkConfig;
import org.apache.calcite.tools.Frameworks;
import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.tools.RelRunners;

import java.io.File;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class CalciteRelBuilderCase {
    public static void main(String[] args) throws SQLException {
        SchemaPlus rootSchema = Frameworks.createRootSchema(true);
        String csvPath = "D:\\study\\codespace\\testcalcite\\src\\main\\resources\\db";
        CsvSchema csvSchema = new CsvSchema(new File(csvPath), CsvTable.Flavor.SCANNABLE);
        rootSchema.add("consumers", csvSchema.getTable("consumers"));
        rootSchema.add("orders", csvSchema.getTable("orders"));

        FrameworkConfig frameworkConfig = Frameworks.newConfigBuilder()
                .parserConfig(SqlParser.Config.DEFAULT)
                .defaultSchema(rootSchema)
                .build();

        RelBuilder relBuilder = RelBuilder.create(frameworkConfig);
//        id,goods,price,amount,user_id               orders
//        id,firstname,lastname,birth                 consumers
        RelNode node = relBuilder
                .scan("consumers")
                .scan("orders")
                .join(JoinRelType.INNER,
                        relBuilder.call(SqlStdOperatorTable.EQUALS,
                                relBuilder.field("id"),
                                relBuilder.field("user_id")))
                .filter(
                        relBuilder.call(SqlStdOperatorTable.EQUALS,
                                relBuilder.field("lastname"),
                                relBuilder.literal("jacky")))
                .project(
                        relBuilder.field("id"),
                        relBuilder.field("goods"),
                        relBuilder.field("price"),
                        relBuilder.field("firstname"),
                        relBuilder.field("lastname"))
                .sortLimit(0, 5, relBuilder.field("id"))
                .build();

        System.out.println(RelOptUtil.toString(node));




        System.out.println("[result:]");
        PreparedStatement run = RelRunners.run(node);
        ResultSet resultSet = run.executeQuery();

        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
        int colCount = resultSetMetaData.getColumnCount();
        for(int i = 1; i <= colCount ; i++){
            System.out.print(resultSetMetaData.getColumnName(i)+"\t");
        }
        System.out.println();

        while(resultSet.next()){
            for(int i = 1; i <= colCount ; i++){
                System.out.print(resultSet.getString(i)+"\t");
            }
            System.out.println();
        }
    }
}

执行结果

代码语言:javascript
复制
LogicalSort(sort0=[$0], dir0=[ASC], fetch=[5])
  LogicalProject(id=[$0], goods=[$5], price=[$6], firstname=[$1], lastname=[$2])
    LogicalFilter(condition=[=($2, 'jacky')])
      LogicalJoin(condition=[=($0, $4)], joinType=[inner])
        LogicalTableScan(table=[[consumers]])
        LogicalTableScan(table=[[orders]])

[result:]
id goods price firstname lastname 
1 book 100 li jacky 

好了,今天的分享就到这里,下次我们来看看如果进行SQL改写。

参考连接

https://calcite.apache.org/docs/algebra.html

https://strongduanmu.com/wiki/calcite/algebra.html

https://zhuanlan.zhihu.com/p/623062311

https://blog.csdn.net/skyyws/article/details/124828049

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-07-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 麒思妙想 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关系代数
    • 代数构建器
      • 扫描表
        • 添加投影
          • 添加过滤聚合
          • 实例 CalciteRelBuilderCase 完整代码
          • 执行结果
          • 参考连接
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档