- 921. Minimum Add to Make Parentheses Valid 使括号有效的最少添加
- 915. Partition Array into Disjoint Intervals 分割数组
- 932. Beautiful Array 漂亮数组
- 940. Distinct Subsequences II 不同的子序列 II
将从各个数据节点获取的多数据结果集,组合成为一个结果集并正确的返回至请求客户端,称为结果归并。也是Sharding 执行过程 SQL解析 => 执行器优化 => SQL路由 => SQL改写 => SQL执行 => 结果归并 的最后一步。
ShardingSphere支持的结果归并从功能上分为遍历、排序、分组、分页和聚合5种类型,它们是组合而非互斥的关系。 从结构划分,可分为流式归并、内存归并和装饰者归并。流式归并和内存归并是互斥的,装饰者归并可以在流式归并和内存归并之上做进一步的处理。
归并引擎主要源码如下
MergeEngineFactory-归并引擎工厂类:
//创建归并引擎的实例 ,根据SQL语句的类型不同,创建DQLMergeEngine或者DALMergeEngine
public static MergeEngine newInstance(final DatabaseType databaseType, final ShardingRule shardingRule,
final SQLStatement sqlStatement, final ShardingTableMetaData shardingTableMetaData, final List<QueryResult> queryResults) throws SQLException {
if (sqlStatement instanceof SelectStatement) {
// 创建DQLMergeEngine实例
return new DQLMergeEngine(databaseType, (SelectStatement) sqlStatement, queryResults);
}
if (sqlStatement instanceof DALStatement) {
return new DALMergeEngine(shardingRule, queryResults, (DALStatement) sqlStatement, shardingTableMetaData);
}
throw new UnsupportedOperationException(String.format("Cannot support type '%s'", sqlStatement.getType()));
}
DQLMergeEngine引擎:
public MergedResult merge() throws SQLException {
if (1 == this.queryResults.size()) {
// 如果只有一个归并的结果集,使用遍历归并(方法内部也只是调用了List.iterator()方法和将返回的结果集赋值给变量)
return new IteratorStreamMergedResult(this.queryResults);
} else {
this.selectStatement.setIndexForItems(this.columnLabelIndexMap);
return this.decorate(this.build());
}
}
private MergedResult build() throws SQLException {
// 判断原生sql 中是否 包含分组语句 + 聚合函数
if (this.selectStatement.getGroupByItems().isEmpty() && this.selectStatement.getAggregationSelectItems().isEmpty()) {
//原生sql 含有排序语句,则使用排序归并,否则使用遍历归并,因为最终返回客户端的结构不需要排序,所以只需多个结果集组合起来
return (MergedResult)(!this.selectStatement.getOrderByItems().isEmpty() ? new OrderByStreamMergedResult(this.queryResults, this.selectStatement.getOrderByItems()) : new IteratorStreamMergedResult(this.queryResults));
} else {
// 分组排序又分为流式分组排序 和 内存分组排序 2种
return this.getGroupByMergedResult();
}
}
private MergedResult getGroupByMergedResult() throws SQLException {
// isSameGroupByAndOrderByItems()方法: retrun !this.getGroupByItems().isEmpty() && this.getGroupByItems().equals(this.getOrderByItems());
return (MergedResult)(this.selectStatement.isSameGroupByAndOrderByItems() ? new GroupByStreamMergedResult(this.columnLabelIndexMap, this.queryResults, this.selectStatement) : new GroupByMemoryMergedResult(this.columnLabelIndexMap, this.queryResults, this.selectStatement));
}
//使用装饰器模式对结果集进行分页归并
private MergedResult decorate(MergedResult mergedResult) throws SQLException {
Limit limit = this.selectStatement.getLimit();
if (null != limit && 1 != this.queryResults.size()) {
//根据数据库类型的不同执行相应的分页结果集归并
if (DatabaseType.MySQL != this.databaseType && DatabaseType.PostgreSQL != this.databaseType && DatabaseType.H2 != this.databaseType) {
if (DatabaseType.Oracle == this.databaseType) {
return new RowNumberDecoratorMergedResult(mergedResult, this.selectStatement.getLimit());
} else {
return (MergedResult)(DatabaseType.SQLServer == this.databaseType ? new TopAndRowNumberDecoratorMergedResult(mergedResult, this.selectStatement.getLimit()) : mergedResult);
}
} else {
return new LimitDecoratorMergedResult(mergedResult, this.selectStatement.getLimit());
}
} else {
return mergedResult;
}
}
它是最为简单的归并方式。在返回的结果集只有一个或者没有使用到排序条件的场景中使用,因为不涉及到排序, 只需将多个数据结果集合并为一个单向链表即可。在遍历完成链表中当前数据结果集之后,将链表元素后移一位,继续遍历下一个数据结果集即可。
在查询SQL中,使用order by 但是没有group by + 聚合函数 的情况下使用,由于在SQL中存在ORDER BY语句,因此每个数据结果集自身是有序的,但各个数据结果集之间是无序的。因此只需要将数据结果集当前游标指向的数据值进行排序即可。 这相当于对多个有序的数组进行排序,归并排序是最适合此场景的排序算法。
ShardingSphere在对排序的查询进行归并时,将每个结果集的当前数据值进行比较(通过实现Java的Comparable接口完成),并将其放入优先级队列。 每次获取下一条数据时,只需将队列顶端结果集的游标下移,并根据新游标重新进入优先级排序队列找到自己的位置即可。
例如当前有三个数据结果集,如下所示:
可以看到,对于每个数据结果集中的数据有序,而多数据结果集整体无序的情况下,ShardingSphere无需将所有的数据都加载至内存即可排序。 它使用的是流式归并的方式,每次next仅获取唯一正确的一条数据,极大的节省了内存的消耗。
从另一个角度来说,ShardingSphere的排序归并,是在维护数据结果集的纵轴和横轴这两个维度的有序性。 纵轴是指每个数据结果集本身,它是天然有序的,它通过包含ORDER BY的SQL所获取。 横轴是指每个数据结果集当前游标所指向的值,它需要通过优先级队列来维护其正确顺序。 每一次数据结果集当前游标的下移,都需要将该数据结果集重新放入优先级队列排序,而只有排列在队列首位的数据结果集才可能发生游标下移的操作。
分组归并的情况最为复杂,它分为流式分组归并和内存分组归并。 流式分组归并要求SQL的排序项与分组项的字段以及排序类型(ASC或DESC)必须保持一致,否则只能通过内存归并才能保证其数据的正确性。
private MergedResult getGroupByMergedResult() throws SQLException {
return (MergedResult)(this.selectStatement.isSameGroupByAndOrderByItems() ? new GroupByStreamMergedResult(this.columnLabelIndexMap, this.queryResults, this.selectStatement) : new GroupByMemoryMergedResult(this.columnLabelIndexMap, this.queryResults, this.selectStatement));
}
public boolean isSameGroupByAndOrderByItems() {
return !this.getGroupByItems().isEmpty() && this.getGroupByItems().equals(this.getOrderByItems());
}
在分组项与排序项完全一致的情况下,取得的数据是连续的,分组所需的数据全数存在于各个数据结果集的当前游标所指向的数据值,因此可以采用流式归并。
举例说明,假设根据科目分片,表结构中包含考生的姓名(为了简单起见,不考虑重名的情况)和分数。通过SQL获取每位考生的总分,可通过如下SQL:
SELECT name, SUM(score) FROM t_score GROUP BY name ORDER BY name;
进行归并时,逻辑与排序归并类似,下图展现了进行next调用的时候,流式分组归并是如何进行的。
通过图中我们可以看到,当进行第一次next调用时,排在队列首位的t_score_java将会被弹出队列,并且将分组值同为“Jetty”的其他结果集中的数据一同弹出队列。 在获取了所有的姓名为“Jetty”的同学的分数之后,进行累加操作,那么,在第一次next调用结束后,取出的结果集是“Jetty”的分数总和。 与此同时,所有的数据结果集中的游标都将下移至数据值“Jetty”的下一个不同的数据值,并且根据数据结果集当前游标指向的值进行重排序。 因此,包含名字顺着第二位的“John”的相关数据结果集则排在的队列的前列。
流式分组归并与排序归并的区别仅仅在于两点:
对于分组项与排序项不一致的情况,由于需要获取分组的相关的数据值并非连续的,因此无法使用流式归并,需要将所有的结果集数据加载至内存中进行分组和聚合。 例如,若通过以下SQL获取每位考生的总分并按照分数从高至低排序,是无法进行流式归并的,只能将结果集的所有数据都遍历并存储在内存中,再通过统一的分组、排序以及聚合等计算之后,再将其封装成为逐条访问的数据结果集返回:
SELECT name, SUM(score) FROM t_score GROUP BY name ORDER BY score DESC;
注意:当SQL中只包含分组语句时,根据不同数据库的实现,其排序的顺序不一定与分组顺序一致。 但由于排序语句的缺失,则表示此SQL并不在意排序顺序。 因此,ShardingSphere通过SQL优化的改写,自动增加与分组项一致的排序项,使其能够从消耗内存的内存分组归并方式转化为流式分组归并方案。
聚合归并是在之前介绍的归并类的之上追加的归并能力,即装饰者模式的一种
无论是流式分组归并还是内存分组归并,对聚合函数的处理都是一致的。 除了分组的SQL之外,不进行分组的SQL也可以使用聚合函数。聚合函数可以归类为比较、累加和求平均值这3种类型
1、 比较类型的聚合函数是指MAX和MIN它们需要对每一个同组的结果集数据进行比较,并且直接返回其最大或最小值即可;
2、 累加类型的聚合函数是指SUM和COUNT它们需要将每一个同组的结果集数据进行累加;
3、 求平均值的聚合函数只有AVG;
上文所述的所有归并类型都可能进行分页。如源码部分所示,merge()归并方法中会调用decorate()进行分页处理。 分页也是追加在其他归并类型之上的装饰器,ShardingSphere通过装饰者模式来增加对数据结果集进行分页的能力。 分页归并负责将无需获取的数据过滤掉。
ShardingSphere 执行分页的处理是通过对SQL的改写来实现的。例如:
SELECT id FROM t_user WHERE age > 18 LIMIT 10000,10
为了保证返回数据的准确性,在SQL改写阶段修改为:SELECT id FROM t_user WHERE age > 18 LIMIT 0,10000
归并引擎的整体结构划分如下图。
以下代码: if (!(ep = engOpen("\0"))) { fprintf(stderr, "\nCan't start MATLAB engine\n");
我在谈论一些网络事物,例如 http://uservoice.com/ 你能推荐任何其他类似的服务、网站,或者可能是(甚至更好)一个现成的引擎来部署在自己的服务器上? 实际上,更多关于系统的问题,可以
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我正在寻找一个矩阵表达式解析器/引擎。例如, 3 * A + B * C 其中 A、B、C 是矩阵是一个典型的表达式。这应该类似于(单值)数学表达式解析器/引擎,但应该处理矩阵值和变量。我已经用谷歌搜
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 5年前关闭。 Improve this qu
是否有基于 .net 的 cometd 引擎?比如 Ajax 推送引擎 那是免费和开源的吗? 最佳答案 轨道式 Orbited是一个 HTTP 守护进程,针对长期 cometd 连接进行了优化。它旨在
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以便
我正在寻找支持以下功能的 haml javascript“端口”: 存储在文件中的模板。 JSON 输入。 支持“集合”[{Booking},{Booking},{Booking}] 进行迭代处理。
我在 IronPython 中托管 IronPython。我没有找到使用等效的命令行参数初始化它的方法:-X:FullFrames . 我的代码有点像这样: import clr clr.AddRef
我想将我工作的公司的所有松散信息整合到一个知识库中。 Wiki 似乎是一种可行的方法,但大部分相关信息都隐藏在 PST 文件中,并且需要很长时间才能说服人们将他们的电子邮件(包括附件)手动翻译成 Wi
我已经使用缓存的 flutter 引擎 flutter 到现有的 native 应用程序(添加到应用程序)中。 override fun onCreate(savedInstanceState: Bu
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我正在使用 Django Cassandra我已经定义了我的模型,我可以用它来命名一个表: class Meta: db_table = "table_name" 但是,Cassand
类似于 NoSQL 数据库,但适用于 OLAP。当然是开源的:) 编辑: OLAP 引擎在幕后使用关系数据库。例如 SAPBW 可以使用 Oracle 等。我的意思是一个没有这个底层关系数据库的 OL
我正在使用以下片段来 enable Razor templating in my solution (在 ASP.NET MVC3 之外)。是否可以轻松实现布局? 背景资料: 我在这一点上(模板编译成
我们目前使用闭源知识库解决方案,所见即所得创建文章是TinyMCE(看起来可能是修改/简化的)。 他们目前根本不允许更改它(添加插件等,除非您可以以某种方式注入(inject)插件)。 我确实拥有对
我正在评估我们的高性能电信应用程序的 BPEL 引擎,但性能似乎很差。我们评估了 Apache Ode、SunBPEL 引擎、Active BPEL 等。您知道任何更快的 BPEL 引擎实现或 C/C
Elastic / Lucene真的需要在文档中存储所有索引数据吗?您难道不就通过通过传递数据,以便Lucene may index the words into its hash table并为每个
我是 3D 游戏新手?我正在使用 Libgdx。如何计算像 Tetromino Revolution 游戏这样的透视相机的参数?请给我任何想法。 看图片:http://www.terminalstud
我是一名优秀的程序员,十分优秀!