Sharding-JDBC源码解析(一)整体流程-CSDN博客
Sharding-JDBC源码解析(二)SQL解析-CSDN博客
Sharding-JDBC源码解析(三)SQL路由-CSDN博客
Sharding-JDBC源码解析(四)SQL改写-CSDN博客
Sharding-JDBC源码解析(五)SQL执行-CSDN博客
Sharding-JDBC源码解析(六)结果归并-CSDN博客
目录
一、整体概述
结果归并就是将从各个数据节点获取的多数据结果集,组合成为一个结果集。
ShardingSphere 支持的结果归并从功能上分为遍历、排序、分组、分页和聚合 5 种类型,它们是组合而非互斥的关系。 从结构划分,可分为流式归并、内存归并和装饰者归并。流式归并和内存归并是互斥的,装饰者归并可以在流式归并和内存归并之上做进一步的处理。
二、详细流程
1.整体流程
public ResultSet getResultSet() throws SQLException {
// 获取各个执行单元返回的结果集
List<ResultSet> resultSets = getResultSets();
// 根据sql选择对应的归并引擎主要有遍历、排序、分组、分页和聚合 5 种类型
MergedResult mergedResult = mergeQuery(getQueryResults(resultSets));
currentResultSet = new ShardingSphereResultSet(resultSets, mergedResult, this, executionContext);
return currentResultSet;
}
2.排序归并
排序归并从结构上看属于流式归并,所以并不需要一次性将所有结果加载到内存中,而是通过一个优先级队列将排序的动作放到每一次获取元素的过程中。
排序归并流程就是分为两步,一是在构造函数中进行初始化排序,二是在每次获取元素(next方法)后的重排序。
2-1.初始变化排序
代码位于OrderByStreamMergedResult#orderResultSetsToQueue
private void orderResultSetsToQueue(final List<QueryResult> queryResults, final SelectStatementContext selectStatementContext, final ShardingSphereSchema schema) throws SQLException {
for (QueryResult each : queryResults) {
// 因为各个结果集都是有序的,所以比较结果集的头节点便可以确认队列的优先级。
OrderByValue orderByValue = new OrderByValue(each, orderByItems, selectStatementContext, schema);
if (orderByValue.next()) {
orderByValuesQueue.offer(orderByValue);
}
}
setCurrentQueryResult(orderByValuesQueue.isEmpty() ? queryResults.get(0) : orderByValuesQueue.peek().getQueryResult());
}
2-2.重排序
代码位于OrderByStreamMergedResult#next,其实就是每次获取完一条数据之后,将结果集中剩下的数据重新排序。
public boolean next() throws SQLException {
if (orderByValuesQueue.isEmpty()) {
return false;
}
if (isFirstNext) {
isFirstNext = false;
return true;
}
OrderByValue firstOrderByValue = orderByValuesQueue.poll();
if (firstOrderByValue.next()) {
orderByValuesQueue.offer(firstOrderByValue);
}
if (orderByValuesQueue.isEmpty()) {
return false;
}
setCurrentQueryResult(orderByValuesQueue.peek().getQueryResult());
return true;
}
3.分页归并
分页归并属于装饰者归并,例如在排序归并的基础上做处理。分页归并也是分为两个过程,一是在构造函数中进行偏移量(offset)处理,二是在每次获取元素(next方法)时判断是否超过limit。
3-1.offset处理
代码入口位于LimitDecoratorMergedResult#skipOffset
private boolean skipOffset() throws SQLException {
// 跳过不需要的行
for (int i = 0; i < pagination.getActualOffset(); i++) {
if (!getMergedResult().next()) {
return true;
}
}
rowNumber = 0;
return false;
}
3-2.limit处理
public boolean next() throws SQLException {
// 是否超出limit
return ++rowNumber <= pagination.getActualRowCount().get() && getMergedResult().next();
}