性能优化案例课程 TPCH-Q15

create view revenue (supplier_no, total_revenue) as
    select
        l_suppkey,
        sum(l_extendedprice * (1 - l_discount))
    from
        lineitem
    where
        l_shipdate >= date '1995-04-01'
        and l_shipdate < date '1995-04-01' + interval '3' month
    group by
        l_suppkey;

select
    s_suppkey,
    s_name,
    s_address,
    s_phone,
    total_revenue
from
    supplier,
    revenue
where
    s_suppkey = supplier_no
    and total_revenue = (
        select
            max(total_revenue)
        from
            revenue
    )
order by
    s_suppkey;

drop view revenue;

生成视图 revenue,与 supplier 关联后再选出含有最大值的记录。

1. 数据存储

lineitem 和 supplier 表没有什么特殊要求,按照主键有序存储。

继续使用题目 Q3 中的 lineitem.ctx 和 Q2 的 supplier.ctx。

将这些表复制到本题的主目录中。

2. 一般实现

这次查询分为两个阶段,先计算出视图 revenue,然后再找出 revenue 中 total_revenue 达到最大值的记录。前者是个常规的分组汇总,利用并行提高性能。

SPL 提供了 A.maxp 方法,可以直接返回最大值所在记录。最大值对应记录数不会太多,可以采用前面题目讲过的大维表查找方法。


A

1

=now()

2

1995-4-1

3

=elapse@m(A2,3)

4

=file("lineitem.ctx").open().cursor@m(L_SUPPKEY,L_EXTENDEDPRICE,L_DISCOUNT;L_SHIPDATE>=A2 && L_SHIPDATE<A3)

5

=A4.groups@u(L_SUPPKEY:supplier_no;sum(L_EXTENDEDPRICE*(1-L_DISCOUNT)):total_revenue)

6

=A5.maxp@a(total_revenue)

7

=file("supplier.ctx").open()

8

=A6.joinx@q(supplier_no,A7:S_SUPPKEY,S_NAME,S_ADDRESS,S_PHONE)

9

=interval@ms(A1,now())

代码中用到了前面讲到过的维表属性化、多线程并行等优化方法。

A8 中采用大维表查找的方法实现 A6 和大维表 supplier 的连接。

测试结果:

测试项目

执行时间(秒)

一般实现

6

3. 数据转换

Lineitem 表中的 L_SHIPDATE 要进行前面介绍的日期整数化。Lineitem 的维表 supplier 要做维表主键序号化,以便采用序号分组。在 Q3 的 lineitem.ctx 和 Q2 的 supplier.ctx 基础上完成维表主键序号化。

还要将 Q2 已经序号化的 supplier_2.ctx 复制到本题的主目录。

数据转换代码:


A

1

=file("supplier.ctx").open().import(S_SUPPKEY).keys@im(S_SUPPKEY)

2

=file("lineitem.ctx").open().cursor()

3

=A2.run(L_SUPPKEY=A1.pfind(L_SUPPKEY),L_SHIPDATE=days@o(L_SHIPDATE))

4

=file("lineitem_15_3.ctx").create@p(#L_ORDERKEY,#L_LINENUMBER,L_PARTKEY, L_SUPPKEY, L_QUANTITY, L_EXTENDEDPRICE,L_DISCOUNT, L_TAX, L_RETURNFLAG, L_LINESTATUS, L_SHIPDATE, L_COMMITDATE, L_RECEIPTDATE,L_SHIPINSTRUCT, L_SHIPMODE, L_COMMENT)

5

>A4.append(A3)

计算代码:


A

1

=now()

2

1995-4-1

3

=days@o(elapse@m(A2,3))

4

=days@o(A2)

5

=file("lineitem_15_3.ctx").open().cursor@m(L_SUPPKEY,L_EXTENDEDPRICE,L_DISCOUNT;L_SHIPDATE>=A4 && L_SHIPDATE<A3)

6

=A5.groups@n(L_SUPPKEY:supplier_no;sum(L_EXTENDEDPRICE*(1-L_DISCOUNT)):total_revenue)

7

=A6.maxp@a(total_revenue)

8

=file("supplier_2.ctx").open()

9

=A7.joinx@q(supplier_no,A8:S_SUPPKEY,S_NAME,S_ADDRESS,S_PHONE)

10

=interval@ms(A1,now())

A6 中 groups@n 是前面介绍过的序号分组。

测试结果:

测试项目

执行时间(秒)

一般实现

6

数据变换

5

4. 列式计算

计算代码:


A

1

=now()

2

1995-4-1

3

=days@o(elapse@m(A2,3))

4

=days@o(A2)

5

=file("lineitem_15_3.ctx").open().cursor@mv(L_SUPPKEY,L_EXTENDEDPRICE,L_DISCOUNT;L_SHIPDATE>=A4 && L_SHIPDATE<A3)

6

=A5.groups@u(L_SUPPKEY:supplier_no;sum(L_EXTENDEDPRICE*(1-L_DISCOUNT)):total_revenue)

7

=A6.maxp@a(total_revenue)

8

=file("supplier_2.ctx").open()

9

=A7.joinx@q(supplier_no,A8:S_SUPPKEY,S_NAME,S_ADDRESS,S_PHONE)

10

=interval@ms(A1,now())

测试结果:

测试项目

执行时间(秒)

一般实现

6

数据转换

5

列式计算

2