Closed heroyf closed 1 year ago
确实,我们需要修复一下这个问题。可以单独作为一个合并请求
这个问题是在实现增强的 ShardingSelector 留下的,主要考虑到的是如果直接在Sharding里执行广播,那 会直接影响findDstByPredicate里 or 分支的逻辑,考虑到这点的话当时是想把这个问题留到具体 sharding 算法实现的时候解决,当然,直接将本issue作为解决也可以
这个问题是在实现增强的 ShardingSelector 留下的,主要考虑到的是如果直接在Sharding里执行广播,那 会直接影响findDstByPredicate里 or 分支的逻辑,考虑到这点的话当时是想把这个问题留到具体 sharding 算法实现的时候解决,当然,直接将本issue作为解决也可以
实际上Or分支,就是会了获取left和right各自分片再去重后的并集,当left返回广播的结果,right返回广播的结果,mergeOr一下是否就是最终的查询语句。
另外mergeOr代码会出现最终的并集出现重复的查询语句
func (*ShardingSelector[T]) mergeOR(left, right sharding.Result) sharding.Result {
dsts := make([]sharding.Dst, 0, len(left.Dsts)+len(right.Dsts))
m := make(map[string]bool, 8)
for _, r := range right.Dsts {
for _, l := range left.Dsts {
if r.NotEquals(l) {
tbl := fmt.Sprintf("%s_%s_%s", l.Name, l.DB, l.Table)
if _, ok := m[tbl]; ok {
continue
}
dsts = append(dsts, l)
m[tbl] = true
}
}
// 这一步会导致重复的元素添加到最终的结果中
dsts = append(dsts, r)
}
return sharding.Result{Dsts: dsts}
}
问题就在这里,左右两边都要广播并求并集,所以考虑到多层嵌套条件的情况,我在这里是比较谨慎的。
我以为是这里的:
if col.name == s.meta.ShardingKey {
shardingDB, err := s.meta.DBShardingFunc(right.val)
if err != nil {
return nil, errs.ErrExcShardingAlgorithm
}
shardingTbl, err := s.meta.TableShardingFunc(right.val)
if err != nil {
return nil, errs.ErrExcShardingAlgorithm
}
_, existDB := s.db.DBs[shardingDB]
if !existDB {
return nil, errs.ErrNotFoundTargetDB
}
_, existTbl := s.db.Tables[shardingTbl]
if !existTbl {
return nil, errs.ErrNotFoundTargetTable
}
dst := Dst{DB: shardingDB, Table: shardingTbl}
res = append(res, dst)
}
在查询条件并不是分库分表键的时候,这里应该返回广播。
@flycash 这里不是之前重构了吗
问题简要描述
分库分表hash、shadow_hash算法不符合预期
select * from
order_db.
order_tablewhere OrderId = '123';
输出的sharding.Query为空SELECT
order_id,
contentFROM
order_db.
order_tab_0WHERE (
user_id=123) OR ((
user_id=181) AND (
user_id=234));
分片结果推理:((181%3=1) AND (234%3=0)),两者交集为空,分片结果为空,所以理论上的输出仅有OR前面user_id=123的分片结果,即预期的单测用户输出条数为1条,但是此单测用例预期是3条输出,不符。复现步骤
复现环境: 仅做分表处理,存在3张表 ordertab{0,1,2},分表算法为UserId%3,UserId为分片键
针对问题1,设计如下单测用例,发现不通过:
上述单测用例,在执行时,输入为
select * from
order_db.
order_tablewhere OrderId = '123';
预期输出为3条查询语句 实际输出为空针对问题2,原有单测用例where or-and all 不符合预期
上述单测用例,在执行时,输入为
SELECT
order_id,
contentFROM
order_db.
order_tab_0WHERE (
user_id=123) OR ((
user_id=181) AND (
user_id=234));
理论预期为1条查询语句即实际输出与单测用例预期输出均为3条
错误日志或者截图
针对问题1,可以看到输出的sharding.Query为空,与预期输出不符
针对问题2,实际单测执行通过,但是与预期不太符合
你期望的结果
执行如下单测能正常通过
你排查的结果,或者你觉得可行的修复方案
实际的分片实现逻辑不对,当传入的查询语句没有找到分片键时,应该做广播处理 理论上应该返回
return sharding.Result{Dsts: h.Broadcast(ctx)}, nil
当然这里修改后,此方法也需要做对应逻辑的调整
func (s *ShardingSelector[T]) findDstByPredicate(ctx context.Context, pre Predicate) (sharding.Result, error)
你使用的是 eorm 哪个版本?
eorm dev分支