多列缓慢聚合

时间:2015-03-26 13:44:09

标签: kdb

聚合多列的kdb查询大约需要31秒,而使用J

需要3秒

有没有更快的方法在kdb中进行求和?

最终这将针对32位版本上的分区数据库运行

/test 1 - using symbols

n: 13000000;
cust: n?`8;
prod: n?`8;
v: n?100
a:([]cust:cust; prod:prod ;v:v)

/query 1 - using simple by
q)\t select sum(v) by cust, prod from a
31058

/query 2 - grouping manually
\t {sum each x[`v][group[flip (x[`cust]; x[`prod])]]}(select v, cust, prod from a)
12887

/query 3 - simpler method of accessing
\t {sum each a.v[group x]} (flip (a.cust;a.prod))
11576

/test 2 - using strings, very slow
n: 13000000;
cust: string n?`8;
prod: string n?`8;
v: n?100
a:([]cust:cust; prod:prod ;v:v)

q)\t select sum(v) by cust, prod from a
116745

比较J代码

n=:13000000
cust=: _8[\ a. {~ (65+?(8*n)#26)
prod=: _8[\ a. {~ (65+?(8*n)#26)
v=: ?.n#100

agg=: 3 : 0 
keys=:i.~ |: i.~ every (cust;prod)
c=.((~.keys) { cust)
p=.((~.keys) { prod)
s=.keys +//. v
c;p;s
)

NB. 3.57 seconds
6!:2 'r=.agg 0'
3.57139

 ({.@$) every r
13000000 13000000 13000000

更新 从kdbplus论坛,我们可以降低速度差异的2倍

q)\t r:(`cust`prod xkey a inds) + select sum v by cust,prod from a til[count a] except inds:(select cust,prod from a) ? d:distinct select cust,prod from a
6809

更新2:为@ user3576050添加了另一个数据集 此数据集具有相同的总行数,但每组分布4个实例

n: 2500000
g: 4
v: (g*n)?100
cust: (g*n)#(n?`8)
prod: (g*n)#(n?`8)
b:([]cust:cust; prod:prod ;v:v)
q)\ts select sum v by cust, prod from b
9737 838861968

上一个查询在新数据集

上运行不佳
q)\ts r:(`cust`prod xkey b inds) + select sum v by cust,prod from a til[count b] except inds:(select cust,prod from b) ? d:distinct select cust,prod from b
17181 671090384

2 个答案:

答案 0 :(得分:2)

如果更新此数据的频率低于查询数据,那么预先计算组索引怎么样?创建单个查询的成本大致相同,它允许以大约30倍的速度查询。

q)\ts select sum v by cust,prod from b
14014 838861360
q)\ts update g:`g#{(key group x)?x}flip(cust;prod)from`b
14934 1058198384
q)\ts select first cust,first prod,sum v by g from b
473 201327488
q)

结果与行顺序和架构详细信息匹配:

q)(select sum v by cust,prod from b)~`cust`prod xasc 2!delete g from select first cust,first prod,sum v by g from b
1b
q)

(顺便说一句,我基本上对J一无所知,但我的猜测是它计算了一个类似的多列组索引。不幸的是,q g索引(目前?)仅限于普通矢量数据 - 如果它有可能以某种方式将它应用于custprod组合,我希望我们会从简单查询中看到类似我的结果。)

答案 1 :(得分:0)

您正在使用病理数据集,一组长度为8的随机符号将很少重复,从而使分组变得多余。

q)n:13000000; (count distinct n?`8)%n
0.9984848
出于同样的原因,p#/ g#属性(在上面的评论中提到)对性能没有影响。

通过更合适的数据,您将看到更好的效果。

q)n:1000000
q)
q)a:([]cust:n?`8; prod:n?`8; v:n?100)
q)b:([]cust:n?`3; prod:n?`3; v:n?100)
q)
q)\ts select sum v by cust, prod from a
3779 92275568
q)
q)\ts select sum v by cust, prod from b
762 58786352