mycat对于分组排序取topN逻辑的处理

在Mycat分片环境中,对分组查询使用limit进行排序时,由于每个分片独立执行带有limit的SQL,可能导致聚合结果不正确。问题在于分片间的排序和限制造成的数据丢失。建议在数据库层做全量分组排序,然后在应用层取topN,但这会增加性能开销。
摘要由CSDN通过智能技术生成

问题描述:

mycat环境: 使用mycat分片,后面挂两个分片shard01 和 shard02

# 分别在分片上创建测试表
create table wjf_test_mycat_orderby (
id   int  not null auto_increment,
name varchar(10) comment '名字',
amt int comment '数量',
primary key (id)
);

# 在 shard01 上执行插入
insert into wjf_test_mycat_orderby values (null,'w',1),(null,'w',1),(null,'w',1),(null,'w',1),(null,'j',1),(null,'j',1);

# 在 shard02 上执行插入
insert into wjf_test_mycat_orderby values (null,'w',1),(null,'w',1),(null,'j',1),(null,'j',1),(null,'j',1),(null,'j',1);


# 连接mycat,执行以下分组排序语句进行测试
select name,sum(amt) sum_amt from wjf_test_mycat_orderby  group by name order by sum_amt desc limit 1;

如果不存在分片的情况下,name 为 'w’的sum数据为6,name 为 ‘j’ 的sum 数据也为6.

测试结果:

guser@99.48.210.224@99.48.210.224 [wjf]>select name,sum(amt) sum_amt from wjf_test_mycat_orderby  group by name order by sum_amt desc limit 1;
+------+---------+
| name | sum_amt |
+------+---------+
| w    |       4 |
+------+---------+
1 row in set (0.01 sec)

guser@99.48.210.224@99.48.210.224 [wjf]>select name,sum(amt) sum_amt from wjf_test_mycat_orderby  group by name ;
+------+---------+
| name | sum_amt |
+------+---------+
| j    |       6 |
| w    |       6 |
+------+---------+
2 rows in set (0.01 sec)

测试结论:

对于分组查询limit的语句,其name 为 w的sum结果为4,是错误的。

问题分析

查看mycat路由分发策略:

2020-11-04 16:40:07.922 DEBUG [$_NIOREACTOR-5-RW] (io.mycat.cache.impl.EnchachePool.get(EnchachePool.java:71)) - SQLRouteCache hit cache ,key:wjfselect name,sum(amt) sum_amt from wjf_test_mycat_orderby  group by name order by sum_amt desc limit 1
2020-11-04 16:40:07.922 DEBUG [$_NIOREACTOR-5-RW] (io.mycat.server.NonBlockingSession.execute(NonBlockingSession.java:126)) - ServerConnection [id=1, schema=wjf, host=99.48.210.224, user=guser,txIsolation=2, autocommit=true, schema=wjf, executeSql=select name,sum(amt) sum_amt from wjf_test_mycat_orderby  group by name order by sum_amt desc limit 1]select name,sum(amt) sum_amt from wjf_test_mycat_orderby  group by name order by sum_amt desc limit 1, route={
   1 -> wjf_1{SELECT name, SUM(amt) AS sum_amt
FROM wjf_test_mycat_orderby
GROUP BY name
ORDER BY sum_amt DESC
LIMIT 1}
   2 -> wjf_2{SELECT name, SUM(amt) AS sum_amt
FROM wjf_test_mycat_orderby
GROUP BY name
ORDER BY sum_amt DESC
LIMIT 1}
   3 -> wjf_3{SELECT name, SUM(amt) AS sum_amt
FROM wjf_test_mycat_orderby
GROUP BY name
ORDER BY sum_amt DESC
LIMIT 1}
   4 -> wjf_4{SELECT name, SUM(amt) AS sum_amt
FROM wjf_test_mycat_orderby
GROUP BY name
ORDER BY sum_amt DESC
LIMIT 1}
} rrs

mycat分发到mysql的语句是带着limit语句的,这样,如果name = ‘w’ 在shard01上排序后是满足条件的,可以查出来。

但是在shard02上排序后不满足条件,没有返回到mycat。

则在mycat层做聚合的时候,缺失了分片2的数据,导致结果不正确。

建议:

在分片库上做分组排序取topN数据的时候,sql语句做全量分组排序,然后在代码层取topN,这样取得数据才能使正确的。

但是全量分组排序,不论在mysql层、mycat层还是在代码层,都会有更多的性能损耗,这点需要考量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值