基于Calcite制作分库分表中间件(方案3)
上次提到模版结合新自定义关系表达式来实现有效的sql生成,那么我们可不可以像方案1中借鉴Calcite现成的功能来实现对之前的方案进行改进.
答案是有的
直观的改进方法有三种
目录
表函数法
org.apache.calcite.rel.core.TableFunctionScan
实际上分库分表的逻辑表可以表述为
形式1:分片函数_表名(单分片值),分片函数_表名(范围分片值)
形式2:分片函数(表名,分片值),分片函数(表名,范围分片值)
分片函数=分片键(拆分键)+算法
而分片分表的谓词分析就是为了提取分片值
逻辑表本身就自带了分片函数信息
所以,直接提取分片值.对逻辑表的分片函数进行赋值,就可以得到对应的物理表范围.
select * from table where id = 1;//table是逻辑表
=>
select * from table(1) where id = 1;
=>
select * from table_0 where id = 1;//table_0是物理表
其中table带有了分片算法的信息,这样就完成了分区剪裁
在使用TableFunctionScan的情况下,可以参考的下推规则是
org.apache.calcite.rel.rules.FilterTableFunctionTransposeRule
View的设计与它是相同,把更多操作放到TableFunctionScan下面,即叶子节点以下.
TableFunctionScan
Filter
RelNode
该方案可以很方便生成以下模板,也可以在生成RelNode,SQLNode的时候把逻辑表名字替换为TableFunctionScan,达到相同效果.
select * from table where condition
=>
select * from table_0 where condition
select * from table_1 where condition
select * from table_2 where condition
也支持使用表函数直接给与分片范围
select * from tableFunction(range,1,10)
当分片函数相同的时候,可以认为它们的物理表的存储分布是相同的,物理表名生成规则也是相同的,在涉及多个相同分片函数的逻辑表带等价关联操作,可以直接把他们的运算下放到存储节点运算.往后的教程我会更详细介绍这个技术.
本质上表函数能做的事情很多,它可以返回结果集,类似支持赋参的View(但不是返回View)
规则下推+自定义关系表达式
org.apache.calcite.interpreter.Bindables.BindableTableScan
BindableTableScan也是一种View,它演示了Project,Filter的下推,是Bindalbe执行器家族的稍微特殊的物理关系表达式
Project
Filter
------------------------------------
Project
TableScan
------------------------------------
TableScan
它本质上也是一种穷举所有关系表达式形态的策略来实现匹配,然后使用枚举所有可以合拼多个关系表达式的特殊节点替换原关系表达式,然后应用规则,然后通过定义的代码完成SQL生成或者执行.
自定义关系表达式+自定义生成执行器实现
org.apache.calcite.adapter.jdbc.JdbcImplementor
public class JdbcImplementor extends RelToSqlConverter {
public JdbcImplementor(SqlDialect dialect, JavaTypeFactory typeFactory) {
super(dialect);
Util.discard(typeFactory);
}
// CHECKSTYLE: IGNORE 1
/** @see #dispatch */
public Result visit(JdbcTableScan scan) {
return result(scan.jdbcTable.tableName(),
ImmutableList.of(Clause.FROM), scan, null);
}
public Result implement(RelNode node) {
return dispatch(node);
}
}
在RelToSqlConverter 帮助下我们可以完成对RelNode生成SQL,在特定的遍历顺序下,我们通过重写阶段生成函数,结合自定义的关系表达式,完成SQL的准确生成.这阶段实际上是在生成执行器的时候进行的.