性能优化案例课程 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 |