千家信息网

性能优化技巧 - 内存关联计算

发表于:2024-11-23 作者:千家信息网编辑
千家信息网最后更新 2024年11月23日,关联动作会严重影响性能,SPL支持内存预关联,可以加快关联动作,从而提升性能。为了理解关联动作对性能的影响,下面设计一套Oracle关联表,以及无关联的宽表,并执行同样的计算。关联表的结构和关系如下:
千家信息网最后更新 2024年11月23日性能优化技巧 - 内存关联计算

关联动作会严重影响性能,SPL支持内存预关联,可以加快关联动作,从而提升性能。

为了理解关联动作对性能的影响,下面设计一套Oracle关联表,以及无关联的宽表,并执行同样的计算。

关联表的结构和关系如下:

数据量:通话记录表(百万条)、用户表(十万条)、开户网点(一万条),代理商表(一万条)。

计算目标:求通讯总成本,即所有呼出用户和呼入用户分别对应的网点均摊成本、代理商均摊成本之和。

将关联结果写入另一张表,形成无关联的宽表:

callRecordWide
SERIALNUMBER
CHARGE
OUTBRANCHOUTCOST
INBRANCHINCOST
OUTAGENTOUTCOST
INAGENTINCOST

下面的SPL脚本,用来说明关联动作对性能的影响:


AB
1=connect("orcl")
2=now()
3for 10=A1.query("select sum(outBranch.outCost+inBranch.inCost+outAgent.outCost+inAgent.inCost) from callRecord,callUser outUser,callUser inUser,telecomBranch outBranch,telecomBranch inBranch,telecomAgent outAgent,telecomAgent inAgent where callRecord.outID=outUser.userID and callRecord.inID=inUser.userID and outUser.branchID=outBranch.branchID and outUser.agentID=outAgent.agentID and inUser.branchID=inBranch.branchID and inUser.agentID=inAgent.agentID")
4=interval@ms(A2,now())/Oracle关联表25802ms
5

6=now()
7for 10=A1.query("select sum(outBranchOutCost+inBranchInCost+outAgentOutCost+inAgentInCost) from callRecordWide")
8=interval@ms(A6,now())/oracle宽表2055ms
9=A1.close()

可以看到,关联比无关联慢12.6倍(25802/2055),会严重影响计算性能。

SPL可以通过预关联来提升关联动作的性能。首先加载数据到内存,代码如下:


AB
1=connect("orcl")
2=A1.query("select * from telecomAgent").keys(AGENTID)
3=A1.query("select * from telecomBranch").keys(BRANCHID)
4=A1.query("select * from callUser").keys(USERID)
5=A1.query("select * from callRecord").keys(SERIALNUMBER)
6=A1.switch(AGENTID,A2:AGENTID; BRANCHID,A3:BRANCHID)
7=A5.switch(OUTID,A14:USERID; INID,A4:USERID)
8=env(callRecord,A7)/全局变量:预关联

函数switch可将字段值替换为记录引用,从而实现预关联。

后续业务算法中,可以直接引用其他表的字段,从而提升关联计算的性能,如下:

=callRecord.sum(OUTID.BRANCHID.OUTCOST+INID.BRANCHID.INCOST

+OUTID.AGENTID.OUTCOST+INID.AGENTID.INCOST)

为了直观理解预关联对计算性能的提升,下面同样用SPL预关联和宽表做比较。


AB
11=connect("orcl")
12=A11.query("select * from telecomAgent").keys(AGENTID)
13=A11.query("select * from telecomBranch").keys(BRANCHID)
14=A11.query("select * from callUser").keys(USERID)
15=A11.query("select * from callRecord").keys(SERIALNUMBER)
16=A14.switch(AGENTID,A12:AGENTID; BRANCHID,A13:BRANCHID)
17=A15.switch(OUTID,A14:USERID; INID,A14:USERID)
18=env(callRecord,A17)/全局变量:预关联
19=A11.query@s("select * from callRecordWide").keys(SERIALNUMBER)
20=env(callRecordWide,A19)/全局变量:宽表
21

22=now()
23for 10

=callRecord.sum(OUTID.BRANCHID.OUTCOST

+INID.BRANCHID.INCOST

+OUTID.AGENTID.OUTCOST+INID.AGENTID.INCOST)

24=interval@ms(A22,now())/SPL预关联13272ms
25

26=now()
27for 10

=callRecordWide.sum(OUTBRANCHOUTCOST

+INBRANCHINCOST+OUTAGENTOUTCOST

+INAGENTINCOST)

28=interval@ms(A26,now())/SPL宽表2210ms

可以看到,预关联比宽表慢6倍(13272/2210),相对于关联表比宽表慢的12.6倍,已经有较大幅度的提升。在宽表时,SPL计算性能和ORACLE几乎相同(2210:2055),但在有关联时,预关联的SPL计算速度已经明显超出临时关联的ORACLE了(13272:25802)。

需要注意的是,上述算法虽然使用了宽表做对比,但并不是说宽表可以代替关联表。事实上,宽表会浪费大量空间,还会造成创建、同步等维护困难,实际项目中很少用到。而预关联使用引用来建立关联,不会创造新表,不会浪费空间,不需要同步数据。


0