性能优化案例课程 TPCH-Q22
select
cntrycode,
count(*) as numcust,
sum(c_acctbal) as totacctbal
from (
select
substr(c_phone,1,2) as cntrycode,
c_acctbal
from
customer
where
substr(c_phone,1,2) in ('11', '14', '15', '19', '20', '21', '23')
and c_acctbal > (
select
avg(c_acctbal)
from
customer
where
c_acctbal > 0.00
and substr(c_phone,1,2) in ('11', '14', '15', '19', '20', '21', '23')
)
and not exists (
select
*
from
orders
where
o_custkey = c_custkey
)
) custsale
group by
cntrycode
order by
cntrycode;
主查询外层是个常规的分组聚合,内层有两个用于条件的子查询。
两个子查询分别对应满足条件的 customer 记录集合,后一个子查询是 not exist,最后结果是两个集合的差集。
1. 数据存储
数据表没有特别的有序要求,都按照主键有序存储。
直接使用 Q3 中的 orders.ctx、customer.ctx,复制到本题的主目录中。
2. 一般实现
计算代码:
A | |
1 | =now() |
2 | =["11","14","15","19","20","21","23"] |
3 | =file("customer.ctx").open().cursor@m(C_CUSTKEY,C_PHONE,C_ACCTBAL;C_ACCTBAL>0.0 && A2.contain(left(C_PHONE,2))).fetch() |
4 | =A3.avg(C_ACCTBAL) |
5 | =A3.select@m(C_ACCTBAL>A4).derive@o().keys@im(C_CUSTKEY) |
6 | =file("orders.ctx").open().cursor@m(O_CUSTKEY;O_CUSTKEY:A5) |
7 | =A6.run(O_CUSTKEY.C_CUSTKEY=null).skip() |
8 | =A5.select@m(C_CUSTKEY) |
9 | =A8.groups(left(C_PHONE,2):cntrycode;count(1):numcust, sum(C_ACCTBAL):totacctbal) |
10 | =interval@ms(A1,now()) |
A5 相当于选出满足第一个子查询条件的记录,A6 中与 A5 关联后选出第二个子查询的记录,A7 中令这些记录的 C_CUSTKEY 为 null,意即从 A5 中删除它们,相当于实现第二个子查询的条件 not exists,A8 中选出的即是满足两个子查询的记录。
测试结果:
测试项目 | 执行时间(秒) |
一般实现 | 6 |
3. 数据转换
本题中要使用前面题目介绍的维表主键序号化方法,把 Q3 的 orders_5.ctx、customer_5.ctx 复制到本题主目录。
计算代码:
A | B | |
1 | =now() | |
2 | =["11","14","15","19","20","21","23"] | |
3 | =file("customer_5.ctx").open() | =A3.cursor@m().skip().(null) |
4 | =A3.cursor@m(C_CUSTKEY,C_ACCTBAL,C_PHONE;C_ACCTBAL>0.0 && A2.contain(left(C_PHONE,2))).fetch().@m(B3(C_CUSTKEY)=~) | |
5 | =B3.avg(C_ACCTBAL) | |
6 | =B3.@m(if(C_ACCTBAL>A5,~,null)) | |
7 | =file("orders_5.ctx").open().cursor@m(O_CUSTKEY;A6(O_CUSTKEY)).run(A6(O_CUSTKEY)=null).skip() | |
8 | =A6.select@m(~).groups@m(left(C_PHONE,2):cntrycode;count(1):numcust, sum(C_ACCTBAL):totacctbal) | |
9 | =interval@ms(A1,now()) |
B3、A6 是对位序列,值是 null 或者 customer 表的记录。
测试结果:
测试项目 | 执行时间(秒) |
一般实现 | 6 |
数据转换 | 2 |
4. 列式计算
计算代码:
A | B | |
1 | =now() | |
2 | =["11","14","15","19","20","21","23"] | |
3 | =file("customer_5.ctx").open() | =A3.cursor@m().skip().(null) |
4 | =A3.cursor@mv(C_CUSTKEY,C_ACCTBAL,C_PHONE;C_ACCTBAL>0.0 && A2.contain(left(C_PHONE,2))).fetch().@m(B3(C_CUSTKEY)=~) | |
5 | =B3.avg(C_ACCTBAL) | |
6 | =B3.@m(if(C_ACCTBAL>A5,~,null)) | |
7 | =file("orders_5.ctx").open().cursor@mv(O_CUSTKEY;A6(O_CUSTKEY)).run(A6(O_CUSTKEY)=null).skip() | |
8 | =A6.select(~).groups@m(left(C_PHONE,2):cntrycode;count(1):numcust, sum(C_ACCTBAL):totacctbal) | |
9 | =interval@ms(A1,now()) |
测试结果:
测试项目 | 执行时间(秒) |
一般实现 | 6 |
数据转换 | 2 |
列式计算 | 1 |
英文版