单表查询之结果合并
接下来以执行SELECT o.* FROM t_order o where o.user_id=10 order by o.order_id desc limit 2,3分析下面这段Java代码是如何对结果进行合并的:
result = new ShardingResultSet(resultSets, new MergeEngine(resultSets, (SelectStatement) routeResult.getSqlStatement()).merge());
MergeEngine.merge()方法的源码如下:
public ResultSetMerger merge() throws SQLException { selectStatement.setIndexForItems(columnLabelIndexMap); return decorate(build()); }
build()方法源码如下:
根据这段代码可知,其作用是根据sql语句选择多个不同的ResultSetMerger对结果进行合并处理,ResultSetMerger实现有这几种:GroupByStreamResultSetMerger,GroupByMemoryResultSetMerger,OrderByStreamResultSetMerger,IteratorStreamResultSetMerger,LimitDecoratorResultSetMerger;以测试SQLSELECT o.* FROM t_order o where o.user_id=10 order by o.order_id desc limit 2,3为例,没有group by,但是有order by,所以使用到了OrderByStreamResultSetMerger和LimitDecoratorResultSetMerger对结果进行合并(GroupByStreamResultSetMerger&GroupByMemoryResultSetMerger后面单独讲解)
decorate()源码如下:
接下来将以执行SQL:SELECT o.* FROM t_order o where o.user_id=10 order by o.order_id desc limit 2,3(该SQL会被改写成SELECT o.* , o.order_id AS ORDER_BY_DERIVED_0 FROM t_order_0 o where o.user_id=? order by o.order_id desc limit 2,3)为例,一一讲解OrderByStreamResultSetMerger,LimitDecoratorResultSetMerger和IteratorStreamResultSetMerger,了解这几个ResultSetMerger的原理;
OrderByStreamResultSetMerger
OrderByStreamResultSetMerger的核心源码如下:
继续深入剖析:这段代码初看可能有点绕,假设运行SQLSELECT o.* FROM t_order o where o.user_id=10 order by o.order_id desc limit 3会分发到两个目标实际表,且第一个实际表返回的结果是1,3,5,7,9;第二个实际表返回的结果是2,4,6,8,10;那么,经过OrderByStreamResultSetMerger的构造方法中的orderResultSetsToQueue()方法后,Queue<OrderByValue> orderByValuesQueue中包含两个OrderByValue,一个是10,一个是9;接下来取值运行过程如下:
- 取得10,并且10的next()是8,然后执行orderByValuesQueue.offer(8);,这时候orderByValuesQueue中包含8和9;
- 取得9,并且9的next()是7,然后执行orderByValuesQueue.offer(7);,这时候orderByValuesQueue中包含7和8;
- 取得8,并且8的next()是6,然后执行orderByValuesQueue.offer(6);,这时候orderByValuesQueue中包含7和6;
- 取值数量已经达到limit 3的限制(源码在LimitDecoratorResultSetMerger中的next()方法中),退出;
这段代码运行示意图如下所示:
LimitDecoratorResultSetMerger
LimitDecoratorResultSetMerger核心源码如下:
IteratorStreamResultSetMerger
构造方法核心源码: