Learn performance optimization skills from TPCH tests - Q17
I. Query Requirement
Q17 queries for small qualities of orders that are lower than 20% of the average supply. This query considers parts of a specified brand and container type and determines the average quantity of such parts for all orders (past and pending) in the seven-year database. If orders that are less than 20% of the average supply are no longer taken, what is the average annual loss? So this query can be used to calculate how much the average annual revenue would be lost if there were no small-quantity orders (because the shipping of parts in large quantities would reduce management costs).
Q17 is characterized by two tables join operations with aggregation and aggregation on sub-query.
II. Oracle Execution
The query SQL written in Oracle is as follows:
select /*+ parallel(n) */
sum(l_extendedprice) / 7.0 as avg_yearly
from
lineitem,part
where
p_partkey = l_partkey
and p_brand = 'Brand#33'
and p_container = 'LG DRUM'
and l_quantity < (
select
0.2 * avg(l_quantity)
from
lineitem
where
l_partkey = p_partkey
);
Where /*+ parallel(n) */ is the parallel query syntax of Oracle, and n is the parallel number.
Script execution time, Unit: seconds
Number of parallel |
1 |
2 |
4 |
8 |
12 |
Oracle |
363 |
278 |
230 |
173 |
165 |
III. SPL Optimization
The equivalent condition association with the primary table in the sub-query can be converted to JOIN to calculate, so that the optimization skill of JOIN can be utilized.
select /*+ parallel(n) */
sum(l_extendedprice) / 7.0 as avg_yearly
from
lineitem,part,
(select l_partkey lp, 0.2*avg(l_quantity) lq
from lineitem
group by l_partkey
) lpq
where
p_partkey = l_partkey
and p_brand = 'Brand#33'
and p_container = 'LG DRUM'
and l_partkey=lp
and l_quantity < lq
This is equivalent to matching and filtering lineitem table twice with foreign key table, one of which is the intermediate table lpq calculated by the sub-query. Because it is an inner join, the partkey involved in the lpq is only in the range of the filtered PART table, so the filtered PART table can be reused.
The SPL script is as follows:
A |
|
1 |
=now() |
2 |
>brand="Brand#33" |
3 |
>container="LG DRUM" |
4 |
=file("part.ctx").open().cursor@m(P_PARTKEY;P_BRAND==brand && P_CONTAINER==container).fetch().keys@im(P_PARTKEY) |
5 |
=file("lineitem.ctx").open() |
6 |
=A5.cursor@m(L_PARTKEY,L_QUANTITY;A4.find(L_PARTKEY)) |
7 |
=A6.groups@u(L_PARTKEY;avg(L_QUANTITY):avg).run(avg/=5).keys@im(L_PARTKEY) |
8 |
=A5.cursor@m(L_PARTKEY,L_QUANTITY,L_EXTENDEDPRICE;L_PARTKEY:A7) |
9 |
=A8.total(sum(if(L_QUANTITY<L_PARTKEY.avg,L_EXTENDEDPRICE,0)))/7.0 |
10 |
return interval@ms(A1,now()) |
Script execution time, Unit: seconds
Number of parallel |
1 |
2 |
4 |
8 |
12 |
Oracle |
363 |
278 |
230 |
173 |
165 |
SPL composite table |
94 |
49 |
26 |
18 |
17 |
SPL Official Website 👉 https://www.scudata.com
SPL Feedback and Help 👉 https://www.reddit.com/r/esProcSPL
SPL Learning Material 👉 https://c.scudata.com
SPL Source Code and Package 👉 https://github.com/SPLWare/esProc
Discord 👉 https://discord.gg/cFTcUNs7
Youtube 👉 https://www.youtube.com/@esProc_SPL