TBase 是基于Postgres-XL 开源项目,演进优化发展而来的 企业级分布式并行计算开源数据库。
TBase is an advanced enterprise-level database management system based on prior work of Postgres-XL project. It supports an extended subset of the SQL standard, including transactions, foreign keys, user-defined types and functions. Additional, it adds parallel computing, security, management, audit and other functions.
Postgres-XL 10R1.1 版本发布后(2019-02-18),后续 停止新版本发布。
Postgres-XL官方网站 Postgres-XL | Open Source Scalable SQL Database Cluster
Postgres-XL 10R1.1 now available! Click here to download the source tarball. (2019-02-18)
TBase是一个提供写可靠性,多主节点数据同步的关系数据库集群平台。你可以将TBase配置一台或者多台主机上,TBase数据存储在多台物理主机上面。数据表的存储有两种方式, 分别是distributed或者replicated ,当向TBase发送查询 SQL时,TBase会自动向数据节点发出查询语句并获取最终结果。
TBase采用分布式集群架构 , 该架构分布式为无共享(share nothing)模式,节点之间相应独立,各自处理自己的数据,处理后的结果可能向上层汇总或在节点间流转,各处理单元之间通过网络协议进行通信,并行处理和扩展能力更好,这也意味着只需要简单的x86服务器就可以部署TBase数据库集群。
解读一下TBase的三大模块
- Coordinator:协调节点(简称CN)业务访问入口,负责数据的分发和查询规划,多个节点位置对等,每个节点都提供相同的数据库视图;在功能上CN上只存储系统的全局元数据,并不存储实际的业务数据。
- Datanode:数据节点(简称DN)每个节点还存储业务数据的分片在功能上,DN节点负责完成执行协调节点分发的执行请求。
- GTM:全局事务管理器(Global Transaction Manager)负责管理集群事务信息,同时管理集群的全局对象,比如序列等。
Q:支持行列混合存储吗?
A:开发的V3版本是支持的,目前开源的V2版本是只支持行存。
Q:扩容后老数据如何清理?
A:我们现在扩容的老数据更多的是通过delete+vacuum的方式做数据的清理,因此老数据清理会对业务造成一些影响。后面会有一些更好的方式来做,比如说做一些数据聚簇的方案,来优化扩容的搬迁和扩容的数据清理对系统的一些影响。
Q :索引膨胀如何解决?
A:若你更新数据或者数据搬迁确实会有索引膨胀,我们建议是重建索引。因为索引重建是可以并行来做的,对业务其实是没有太大的影响,索引建好后把老的索引删掉就OK了。
++++++++++++++++++++++++++++++++++++++++++++
===Tbase === 源码【语义分析】部分 沿用了PostgreSQL的源码。
【查询重写】部分依然沿用PostgreSQL的源码srcbackend copPostgres.c,入口函数是:pg_rewrite_query 。
【查询优化——预处理】查询优化模块的入口函数是pg_plan_queries函数 srcbackend copPostgres.c,它负责将查询树链表变成执行计划链表。
Utility commands 不需要执行计划
非 Utility commands,
srcbackendoptimizerplanPlanner.c
CN 节点调用 pgxc_planner(parse, cursorOptions, boundParams);
DN节点调用standard_planner(parse, cursorOptions, boundParams);
srcbackendoptimizerplanPlanner.c
CN 节点调用 pgxc_planner(parse, cursorOptions, boundParams);
srcbackendoptimizerplanPlanner.c
srcbackendoptimizerplanPlanner.c
standard_planner(parse, cursorOptions, boundParams);
standard_planner函数调用的——subquery_planner函数 subquery_planner 函数接受Query查询树,最后通过PlannedStmt结构体的形式返回Plan计划树。(Plan计划树被封装在PlannedStmt结构体中)subquery_planner函数负责创建计划,可以递归处理子查询。subquery_planner函数的工作分为两个部分: 1:依据消除冗余条件,减少查询层次,简化路径生成的基本思想,调用预处理函数对查询树进行处理 2:调用inheritance_planner 或者grouping_planner进入生成计划流程,此过程不对查询树做出实质性改变
srcbackendoptimizerplanPlanner.c
子链接和子查询的区别:子查询是一条完整的查询语句,而子链接是一条表达式,但是表达式内部也可以包含查询语句。直白点说呢就是:子查询是放在FROM子句里的而子链接则出现在WHERE子句或者HAVING子句中。 在subquery_planner函数里,调用pull_up_sublinks函数处理WHERE子句和JOIN/ON子句中的ANY和EXISTS类型的子链接。
subquery_planner函数调用pull_up_subqueries函数来提升子查询。当子查询仅仅是一个简单的扫描或者连接时,就会把子查询或者子查询的一部分合并到父查询中以进行优化。 1.在范围表中存在子查询。对于简单的子查询,直接调用pull_up_simple_subquery函数进行提升;而对于简单的UNION ALL子查询,调用pull_up_simple_union_all函数进行提升,其他的情况则不处理; 2.在FROM表达式中存在子查询。对于FROM列表中的每个节点都调用pull_up_subqueries递归处理; 3.连接表达式中的子查询。调用pull_up_subqueries函数递归地处理.
表达式的预处理工作主要由函数preprocess_expression完成。该函数采用递归扫描的方式处理PlannerInfo结构体里面保存的目标属性、HAVING子句、OFFSET子句、LIMIT子句和连接树jointree。总体来说做了以下这些事 1.调用flatten_join_alias_vars函数,用基本关系变量取代连接别名变量; 2.调用函数eval_const_expression进行常量表达式的简化,也就是直接计算出常量表达式的值。例如:“3+1 <> 4” 这种会直接被替换成“FALSE”; 3.调用canonicalize_qual函数对表达式进行规范化,主要是将表达式转换为最佳析取范式或者合取范式 4.调用函数make_subplan将子链接转换为子计划.
srcbackendoptimizerplanPlanner.c
process_sublinks_mutator 引用了make_subplan 函数
函数make_subplan, 其执行步骤如下:
1)首先复制子链接SubLink中的查询树Query,如果查询树是一个EXISTS型的子计划,那么则调用simplify_EXISTS_query函数对QUery副本进行处理; 2)调用subquery_planner函数为子链接生成计划,同时设置好参数tuple_fraction来告诉底层规划器需要去多少个元组。对于EXISTS型的子查询,设置该值为1.0,取回一个元组即可;对于ALL和ANY型的子查询,从概率上说大约取到50%的元组就可以得到结果,因此设置参数值为0.5;对于其他的查询,统一设置为0; 3)调用build_subplan函数将上一步生成的计划转换为SubPlan或者InitPlan的形式,并将当前查询层次的参数列表传递给它的子计划; 4)对于生成的是SubPlan而且是一个简单的EXISTS类型的查询,调用convert_EXISTS_to_ANY函数尝试将其转换为一个ANY类型的查询并创建查询计划.
处理HAVING子句
对于HAVING子句来说,除了进行前面所提到的预处理外,还需要处理其中的每个条件。如果HAVING子句中没有聚集函数的话,那么它完全可以退化到WHERE子句中去,否则的话他将被写到查询树的HavingQual字段里面。