详探 Apache ShardingSphere SQL Parse Format 功能

419c1b69214edeeb6ba1154e8bd106a7.png

陈出新

SphereEx 中间件研发工程师,Apache ShardingSphere Committer,目前专注于 Apache ShardingSphere 内核模块的研发工作。

经常使用数据库的朋友们一定见过无比复杂的 SQL,以下面的 SQL 语句为例,你能立刻看出来这条 SQL 的含义吗?

select a.order_id,a.status,sum(b.money) as money from t_order a inner join (select c.order_id as order_id, c.number * d.price as money from t_order_detail c inner join t_order_price d on c.s_id = d.s_id) b on a.order_id = b.order_id where b.money > 100 group by a.order_id

经过格式化之后是不是容易理解多了:

SELECT a . order_id , a . status , SUM(b . money) AS money
FROM t_order a INNER JOIN 
(
        SELECT c . order_id AS order_id, c . number * d . price AS money
        FROM t_order_detail c INNER JOIN t_order_price d ON c . s_id = d . s_id
) b ON a . order_id = b . order_id
WHERE 
        b . money > 100
GROUP BY a . order_id;

相信大家拿到复杂 SQL 分析的第一步就是格式化这个 SQL,然后才能基于格式化之后的内容进一步分析 SQL 语义。SQL 的格式化功能也是众多数据库相关软件的必备功能之一。Apache ShardingSphere 基于这样的需求,依托自带的数据库方言解析引擎,推出了自己的 SQL 格式化工具——SQL Parse Format。

SQL Parse Format 是 Apache ShardingSphere 解析引擎的功能之一,也将是未来规划版本中 SQL 审计功能的基础。本文将带领读者深入浅出地理解 SQL Parse Format 功能,了解它的底层原理、使用方式以及如何参与 SQL Parse Format 开发。

Parser Engine

SQL Parse Format 作为 Apache ShardingSphere 解析引擎的功能之一,是解析引擎中独特并且相对独立的功能。要理解 SQL Parse Format 功能,需要首先需要了解 Apache ShardingSphere 的解析引擎。

Apache ShardingSphere 解析引擎创建的初衷是为了提取 SQL 中的关键信息,例如用于分库分表的字段、加密改写的列等等内容。随着 Apache ShardingSphere 的不断发展,解析引擎也经历了 3 代产品的更新迭代。

第一代解析引擎采用 Druid 作为 SQL 解析器,它在 1.4.x 之前的版本使用,性能优异。第二代解析引擎采用了全自研的方式,由于使用目的不同,第二代产品采用对 SQL 半理解的方式,仅仅提取分片数据关心的上下文信息,无需生成解析树,也不用二次遍历,因此性能和兼容性进一步提升。第三代解析引擎采用 ANTLR 作为解析引擎的生成器,从而生成解析树,然后再对解析树进行二次遍历访问提取上下文信息。利用 ANTLR 作为解析引擎生成器之后,SQL 的兼容性得以大幅提升,Apache ShardingSphere 的众多功能也能够基于这个基础快速展开。5.0.x 的版本也对第三代解析引擎进行了大量的性能优化,包括将遍历方式从 Listener 变为 Visitor,为预编译的 SQL 语句添加解析结果缓存等等。

SQL Parse Format 功能的实现正是得益于第三代解析引擎的创建。接下来,就让我们将目光聚集到 SQL Parse Format 功能之上。

SQL Parse Format

SQL Parse Format 是一款 SQL 语句格式化的工具。SQL Parse Format 功能将来还会用于 SQL 审计功能之中,它可以方便用户查看历史 SQL 、通过报表展示格式化的 SQL 或者对 SQL 作进一步的分析处理。

例如如下 SQL 经过 SQL Parse Format 格式化之后会变成以下格式。它通过换行和关键字大写的方式让 SQL 的各个部分更加突出和清晰。

select age as b, name as n from table1 join table2 where id = 1 and name = 'lu';
-- 格式化
SELECT age AS b, name AS n
FROM table1 JOIN table2
WHERE 
        id = 1
        and name = 'lu';

了解了 SQL Parse Format 的基本功能之后,让我们一起来探究 SQL Parse Format 背后的原理。

SQL Parse Format 原理解读

以如下 SQL 为例,我们来一起探究它在 Apache ShardingSphere 中是如何被格式化的。

select order_id from t_order where status = 'OK'

Apache ShardingSphere 采用了 ANTLR4 作为解析引擎生成器工具,所以我们首先按照 ANTLR4 的方式,在 .g4 文件中定义了 select 的语法(以 MySQL 为例)。

simpleSelect
    : SELECT ALL? targetList? intoClause? fromClause? whereClause? groupClause? havingClause? windowClause?
    | SELECT distinctClause targetList intoClause? fromClause? whereClause? groupClause? havingClause? windowClause?
    | valuesClause
    | TABLE relationExpr
    ;

我们通过 IDEA 的 ANTLR4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是使用Flink SQL连接SSL Kafka的示例代码(适用于Flink 1.17.0版本): ```java import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.table.api.bridge.java.StreamTableEnvironment; import org.apache.flink.table.api.EnvironmentSettings; import org.apache.flink.table.api.Table; import org.apache.flink.table.api.TableResult; import org.apache.flink.table.descriptors.*; import org.apache.flink.types.Row; public class SSLKafkaDemo { public static void main(String[] args) throws Exception { // set up the execution environment StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env, EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build()); // set up the Kafka connector properties final String topic = "test-topic"; final String kafkaBootstrapServers = "kafka-broker-1:9092,kafka-broker-2:9092,kafka-broker-3:9092"; final String kafkaSecurityProtocol = "SSL"; final String kafkaSslTruststoreLocation = "/path/to/kafka.client.truststore.jks"; final String kafkaSslTruststorePassword = "password"; // set up the Kafka connector descriptor Kafka kafka = new Kafka() .version("universal") .topic(topic) .property("bootstrap.servers", kafkaBootstrapServers) .property("security.protocol", kafkaSecurityProtocol) .property("ssl.truststore.location", kafkaSslTruststoreLocation) .property("ssl.truststore.password", kafkaSslTruststorePassword); // set up the schema of the Kafka connector Schema schema = Schema.newBuilder() .column("key", DataTypes.STRING()) .column("value", DataTypes.STRING()) .column("timestamp", DataTypes.TIMESTAMP(3)) .build(); // set up the format of the Kafka connector Json json = new Json() .failOnMissingField(false) .deriveSchema(); // create the Kafka table and register it in the table environment tableEnv .executeSql("CREATE TABLE kafka_table (\n" + " `key` STRING,\n" + " `value` STRING,\n" + " `timestamp` TIMESTAMP(3)\n" + ") WITH (\n" + " 'connector' = 'kafka',\n" + " 'topic' = '" + topic + "',\n" + " 'properties.bootstrap.servers' = '" + kafkaBootstrapServers + "',\n" + " 'properties.security.protocol' = '" + kafkaSecurityProtocol + "',\n" + " 'properties.ssl.truststore.location' = '" + kafkaSslTruststoreLocation + "',\n" + " 'properties.ssl.truststore.password' = '" + kafkaSslTruststorePassword + "',\n" + " 'format' = 'json',\n" + " 'json.fail-on-missing-field' = 'false',\n" + " 'json.ignore-parse-errors' = 'true',\n" + " 'json.timestamp-format.standard' = 'ISO-8601'\n" + ")"); // execute a SQL query on the Kafka table TableResult result = tableEnv.executeSql("SELECT * FROM kafka_table WHERE `key` = 'foo'"); // print the result of the query result.print(); // execute the Flink job env.execute(); } } ``` 请确保将`kafkaSecurityProtocol`设置为`SSL`,并提供SSL证书的路径和密码。此外,还需要配置`Json`格式以从Kafka接收和发送数据。这个示例代码使用了Table API的方式来创建并注册Kafka表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值