【死磕Sharding-jdbc】—&#8211...
zhangmin
zhangmin 785 0
2019-09-23 14:07
文水电子商务。商务合作QQ:群:483714163
撸了今年阿里、腾讯和美团的面试,我有一个重要发现…….

原文作者:阿飞Javaer
 原文链接:https://www.jianshu.com/p/e541ac380e18
这篇文章源于sharding-jdbc源码分析之重写的遗留问题,相关sharding-jdbc源码如下:
private void appendLimitRowCount(final SQLBuilder sqlBuilder, final RowCountToken rowCountToken, final int count, final List sqlTokens, final boolean isRewrite) { SelectStatement selectStatement = (SelectStatement) sqlStatement; Limit limit = selectStatement.getLimit(); if (!isRewrite) { ... ... } else if ((!selectStatement.getGroupByItems().isEmpty() || !selectStatement.getAggregationSelectItems().isEmpty()) && !selectStatement.isSameGroupByAndOrderByItems()) { // 如果要重写sql中的limit的话,且sql中有group by或者有group by & order by,例如"select user_id, sum(score) from t_order group by user_id order by sum(score) desc limit 5",那么limit 5需要重写为limit Integer.MAX_VALUE,原因接下来分析 sqlBuilder.appendLiterals(String.valueOf(Integer.MAX_VALUE)); } else { ... ... } ... ...}构造数据

为了解释为什么limit rowCount中的rowCount需要重写为Integer.MAX_VALUE,需要先构造一些数据,如下图所示:

如果不分库分表的话,数据如下图所示:

执行SQL

假定执行如下SQL:
select user_id, sum(score) from t_order group by user_id order by sum(score) desc limit 5;结果如下所示:

假定select user_id, sum(score) from t_order group by user_id order by sum(score) desc limit 5;这个SQL不重写为limit 0, Integer.MAX_VALUE,那么t_order_0和t_order_1的结果分别如下;
t_order_0的结果:

t_order_1的结果:

路由到两个表的执行结果归并后的结果如下:

分析

根据执行结果可知,主要差异在于,真实结果有user_id为20,21的数据。我们在看一下t_order_0和t_order_1两个分表中这两个user_id的数据有什么特殊之处:

在t_order_1这个分表中,由于user_id为20,21的score值在TOP 5以外。但是合并t_order_0和t_order_1两个分表的结果,user_id为20的sum(score)能够排在第一(18+18=36);所以,如果group by这类的SQL不重写为limit 0, Integer.MAX_VALUE的话,会导致结果有误。所以sharding-jdbc的源码必须要这样重写,没有其他办法!
延伸

事实上不只是sharding-jdbc,任何有sharding概念的中间件例如es,都要这么处理,因为sharding后数据处理的流程几乎都要经过解析->重写->路由->执行->结果归并这几个阶段;

本文内容来源文水手机台,如有侵权请立即与我们联系,我们将及时处理!
分享:
游客
要评论请先登录 或者 注册
返回顶部