2 获取表名_分库分表系列(2)-shardingsphere内核解析

本文详细介绍了ShardingSphere的内核工作流程,包括SQL解析、执行器优化、分片路由、SQL改写和结果归并。重点讲解了SQL解析的词法和语法分析,以及路由引擎的直接路由、标准路由和笛卡尔积路由策略。此外,还涵盖了广播路由的各种类型,如全库表路由、全库路由等。
摘要由CSDN通过智能技术生成

5ed3a5d43025697b2455e74b53cdb827.png

shardingsphere内核解析, 主要关注SQL解析, 路由引擎, 结果归并等

执行顺序

  • SQL 解析
  • 执行器优化
  • SQL 路由
  • SQL 改写
  • SQL 执行
  • 结果归并

SQL处理的核心由SQL 解析 => 执行器优化 => SQL 路由 => SQL 改写 => SQL 执行 => 结果归并的流程组成。

5557831162632e2789dae576d9adde8c.png
  1. SQL 解析

分为词法解析和语法解析。 先通过词法解析器将 SQL 拆分为一个个不可再分的单词。再使用语法解析器对 SQL 进行理解,并最终提炼出解析上下文。 解析上下文包括表、选择项、排序项、分组项、聚合函数、分页信息、查询条件以及可能需要修改的占位符的标记

2. 执行器优化

合并和优化分片条件,如 OR 等。

3. SQL 路由

根据解析上下文匹配用户配置的分片策略,并生成路由路径。目前支持分片路由和广播路由。

4. SQL 改写

将 SQL 改写为在真实数据库中可以正确执行的语句。SQL 改写分为正确性改写和优化改写。

5. SQL 执行

通过多线程执行器异步执行。

6. 结果归并

将多个执行结果集归并以便于通过统一的 JDBC 接口输出。结果归并包括流式归并、内存归并和使用装饰者模式的追加归并这几种方式。

引擎

  • 解析引擎

主要用于SQL语法的解析, 解析过程包括词法和语法分析.词法解析器用于将 SQL 拆解为不可再分的原子符号,称为 Token。并根据不同数据库方言所提供的字典,将其归类为关键字,表达式,字面量和操作符。 再使用语法解析器将 SQL 转换为抽象语法树。

例如:

SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18

解析后语法树如下:

b95ed3da35a1cde00e942d290e6d5007.png
  • 路由引擎

包括分片路由和广播路由, 用于根据分片键进行路由的场景,又细分为直接路由、标准路由和笛卡尔积路由这 3 种类型。

  1. 分片路由

a. 直接路由

满足直接路由的条件相对苛刻,它需要通过 Hint(使用 HintAPI 直接指定路由至库表)方式分片,并且是只分库不分表的前提下,则可以避免 SQL 解析和之后的结果归并。 因此它的兼容性最好,可以执行包括子查询、自定义函数等复杂情况的任意 SQL。直接路由还可以用于分片键不在 SQL 中的场景。例如,设置用于数据库分片的键为3

hintManager.setDatabaseShardingValue(3);

如路由算法为 value % 2,当一个逻辑库 t_order 对应 2 个真实库 t_order_0t_order_1 时,路由后 SQL 将在 t_order_1 上执行。下方是使用 API 的代码样例:

String sql = "SELECT * FROM t_order";
try (
        HintManager hintManager = HintManager.getInstance();
        Connection conn = dataSource.getConnection();
        PreparedStatement pstmt = conn.prepareStatement(sql)) {
    hintManager.setDatabaseShardingValue(3);
    try (ResultSet rs = pstmt.executeQuery()) {
        while (rs.next()) {
            //...
        }
    }
}标准路由

b. 标准路由

标准路由是 ShardingSphere 最为推荐使用的分片方式,它的适用范围是不包含关联查询或仅包含绑定表之间关联查询的 SQL。 当分片运算符是等于号时,路由结果将落入单库(表),当分片运算符是 BETWEEN 或 IN 时,则路由结果不一定落入唯一的库(表),因此一条逻辑 SQL 最终可能被拆分为多条用于执行的真实 SQL。 举例说明,如果按照 order_id 的奇数和偶数进行数据分片,一个单表查询的 SQL 如下:

SELECT * FROM t_order WHERE order_id IN (1, 2);

那么路由的结果应为:

SELECT * FROM t_order_0 WHERE order_id IN (1, 2);
SELECT * FROM t_order_1 WHERE order_id IN (1, 2);

绑定表的关联查询与单表查询复杂度和性能相当。举例说明,如果一个包含绑定表的关联查询的 SQL 如下:

SELECT * FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id  WHERE order_id IN (1, 2);

那么路由的结果应为:

SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id  WHERE order_id IN (1, 2);
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id  WHERE order_id IN (1, 2);

可以看到,SQL 拆分的数目与单表是一致的。

c. 笛卡尔积路由

卡尔路由是最复杂的情况,它无法根据绑定表的关系定位分片规则,因此非绑定表之间的关联查询需要拆解为笛卡尔积组合执行。 如果上个示例中的 SQL 并未配置绑定表关系,那么路由的结果应为:

SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id  WHERE order_id IN (1, 2);
SELECT * FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id  WHERE order_id IN (1, 2);
SELECT * FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id  WHERE order_id IN (1, 2);
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id  WHERE order_id IN (1, 2);

笛卡尔路由查询性能较低,需谨慎使用。

2. 广播路由

对于不携带分片键的 SQL,则采取广播路由的方式。根据 SQL 类型又可以划分为全库表路由、全库路由、全实例路由、单播路由和阻断路由这 5 种类型

a. 全库表路由

全库表路由用于处理对数据库中与其逻辑表相关的所有真实表的操作,主要包括不带分片键的 DQL 和 DML,以及 DDL 等。例如:

SELECT * FROM t_order WHERE good_prority IN (1, 10);

则会遍历所有数据库中的所有表,逐一匹配逻辑表和真实表名,能够匹配得上则执行。路由后成为

SELECT * FROM t_order_0 WHERE good_prority IN (1, 10);
SELECT * FROM t_order_1 WHERE good_prority IN (1, 10);
SELECT * FROM t_order_2 WHERE good_prority IN (1, 10);
SELECT * FROM t_order_3 WHERE good_prority IN (1, 10);

b. 全库路由

全库路由用于处理对数据库的操作,包括用于库设置的 SET 类型的数据库管理命令,以及 TCL 这样的事务控制语句。 在这种情况下,会根据逻辑库的名字遍历所有符合名字匹配的真实库,并在真实库中执行该命令,例如:

SET autocommit=0;

t_order 中执行,t_order 有 2 个真实库。则实际会在 t_order_0t_order_1 上都执行这个命令。

c. 全实例路由

全实例路由用于 DCL 操作,授权语句针对的是数据库的实例。无论一个实例中包含多少个 Schema,每个数据库的实例只执行一次。例如:

CREATE USER customer@127.0.0.1 identified BY '123';

这个命令将在所有的真实数据库实例中执行,以确保 customer 用户可以访问每一个实例。

d. 单播路由

单播路由用于获取某一真实表信息的场景,它仅需要从任意库中的任意真实表中获取数据即可。例如:

DESCRIBE t_order;

t_order 的两个真实表 t_order_0,t_order_1 的描述结构相同,所以这个命令在任意真实表上选择执行一次。

e. 阻断路由

断路由用于屏蔽 SQL 对数据库的操作,例如:

USE order_db;

这个命令不会在真实数据库中执行,因为 ShardingSphere 采用的是逻辑 Schema 的方式,无需将切换数据库 Schema 的命令发送至数据库中

2cc47d33876f074022eea558ab5391e3.png

参考: ShardingSphere

1b442aee2ba6ae88d22affe9c451e896.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值