Kdb 多列上的慢速聚合

Kdb 多列上的慢速聚合,kdb,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 /quer

这个聚合多个列的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

如果您使用的是病理数据集,那么一组长度为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

如果更新此数据的频率低于查询此数据的频率,那么预计算组索引如何?创建一个查询的成本与创建一个查询的成本差不多,并且它允许以大约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基本一无所知,但我猜测它正在计算一个类似的多列组索引仅限于纯向量数据,如果可以以某种方式将其应用于
cust
prod
的组合,我希望我们可以从简单查询中看到与我类似的结果。)

查询本身非常简单,但您可以尝试将parted或group属性应用于cust和/或prod,这将使它运行得更快(以实际访问属性所花费的初始时间为代价),谢谢,根据我的实际数据,我确实有g#属性,但它似乎没有帮助。可能是g#属性在分区间的工作效率不高?奇怪的是
p
g
属性都会产生一些影响。我能想到的另一件事是将表分成更小的子集,类似于我发现很难相信kdb在公平的比较中会慢近10倍,但我不知道J,所以无法检查您的J代码。你确定你没有在J代码中预先计算一些东西吗?@terrylynch-在J代码中没有预先计算任何东西。谢谢,我在上面添加了一个更具代表性的示例,它仍然比J代码运行得慢