在Go中实现汇总的最佳方法(例如SQL中的GROUP BY)?

时间:2019-06-28 23:08:31

标签: go

假设我有一个结构

type row struct {
    f1, f2, f3 string
    v int64
}

我们可以把它想象成表中的一行。

此外,我需要实现一个可以像以下查询那样进行聚合的函数:

SELECT f1, f2, f3, SUM(v) FROM table GROUP BY f1, f2, f3

所以,我必须实现功能:

type key struct {
    f1, f2, f3 string
}
func aggregate(t []row) map[key]int64

或者如果可以的话

func aggregate(t []row) map[string]row

其中映射键为f1 + f2 + f3

func aggregate(t []row)  []row

如果结果将包含唯一的f1,f2,f3组合(DISTINCT f1,f2,f3),也可以使用

我有两个变体:

func aggregate1(t []row) map[key]int64 {
    res := map[key]int64{}
    for _, r := range t {
        res[key{r.f1, r.f2, r.f3}] += r.v
    }
    return res
}
func aggregate2(t []row) map[string]*row {
    res := map[string]*row{}
    for _, r := range t {
        var sb strings.Builder
        sb.WriteString(r.f1)
        sb.WriteString("#")
        sb.WriteString(r.f2)
        sb.WriteString("#")
        sb.WriteString(r.f3)
        id := sb.String()
        t := res[id]
        if t == nil {
            t = &row{f1: r.f1, f2: r.f2, f3: r.f3, v: 0}
            res[id] = t
        }
        t.v += r.v
    }
    return res
}

第一个变体在https://golang.org/pkg/runtime/?m=all#mapassign(runtime.mapassign)中花费太多时间

第二个变体的想法是使用更快的https://golang.org/pkg/runtime/?m=all#mapassign_faststr(runtime.mapassign_faststr),但是strings.Builder.WriteString消除了runtime.mapassign_faststr的所有好处:(

那么,您能建议更多有关如何实现此聚合的想法吗?

我正在考虑如何在第二个变体中有效地计算“ id”。它应该是唯一的。我的变体是唯一的,因为f1,f2和f3不能包含“#”字符。

0 个答案:

没有答案