Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

分库分表:结果集处理——聚合函数(含 Group By 子句) #191

Closed
Tracked by #182
juniaoshaonian opened this issue Apr 15, 2023 · 1 comment · Fixed by #193
Closed
Tracked by #182

分库分表:结果集处理——聚合函数(含 Group By 子句) #191

juniaoshaonian opened this issue Apr 15, 2023 · 1 comment · Fixed by #193
Labels

Comments

@juniaoshaonian
Copy link
Collaborator

juniaoshaonian commented Apr 15, 2023

仅限中文

使用场景

分组键的选择

● 分组键是shardingkey
如果是shardingkey的情况,意味着一个组的元素只会在一个sql.Rows中,逻辑和batchMerger差不多,一条一条从sqlRows里面拿数据就可以了。我们可以直接复用即可
● 分组键不是shardingkey
不是shardingkey的情况就比较恶心一点了,意味着一个组的元素可能分布在多个sql.Rows。我们需要拿到全部数据然后根据分组键的信息拿到同一个组的信息,进行merger计算。
这种计算方式很显然如果数据量比较大会导致内存占用过多。这个问题比较难解决。用户可以自己通过控制结果集大小来控制内存大小。对这方面我们不做控制。因为我们无法得知用户的具体一行有多大数据。我们到底是1000条去进行限制还是说2000条。

分组信息的匹配

由于我们需要根据分组键的信息去找到相同组的数据,查询的时候就需要携带上分组键的信息。比如 select actorid,SUM(filmid) group by actorid。这个sql是查演员有多少部电影作品。在merger计算的时候需要通过actorid在sqlRows列表中找到相同actorid的数据。当然这个是针对分组键不是shardingkey的情况。

设计

type GroupByMerger struct {
    	groupKeys []string
    }
    
    func (g GroupByMerger) Merge(ctx context.Context, results []*sql.Rows) (merger.Rows, error) {
    	// 将数据拿出,这部分没什么需要特别注意的。和之前差不多
    
    	// 怎样将数据进行保存,我想到的是用map进行保存,key用groupKey,value使用[][]any表示多个需要merger的数据行进行聚合计算的时候就将value作为参数传入聚合函数的实现。
    	// 但这个有个问题分组键可能是不同数据类型的,我们如何将他们转化成key呢?
    }
    剩余的rows的next就是设置个游标从保存数据的地方取出数据进行聚合函数计算就行了

@flycash
Copy link
Contributor

flycash commented Apr 19, 2023

但这个有个问题分组键可能是不同数据类型的,我们如何将他们转化成key呢
这个可以考虑使用 ekit 里面的 TreeMap。然后 Key 本身被定义成一个结构体:

type Key struct {
    columnValues []any
}

这个 Key 本身会实现 Compare 的方法,那么在 Compare 的时候就直接比较 columnValues 就可以了。也就是类似于从左到右比较每一个元素,比如说最开始是 a.columnValues[0],然后 if a.columnValues[0] > b.columnValues[0] 那么就是 a 比较大。如果全部都相等,那么就相等。

这里会有一个问题,就是代码可能比较呆,因为你在这里也不太能够用泛型。比如说 columnValues 里面的元素可能是基本类型,sql.NullXXX 类型,字节数组类型。不过这部分内容你在排序里面已经处理过一次了,实际上是可以复用的。

你需要小心设计测试用例,要覆盖不同的 GROUP BY 的列的元素类型。还要额外考虑:

  • GROUP BY 是 shard key 和非 shard key 混合的
  • 完全非 shard key 的
    不过理论上来说,其实你 GROUP BY 是根本不管这个列是不是 SK 的,应该调用者自己去判断是不是全部都是 SK。

@flycash flycash linked a pull request Apr 24, 2023 that will close this issue
@flycash flycash closed this as completed Apr 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants