大主子表之间进行 EXISTS 计算往往会导致较差的性能。这样的计算本质上是在做主键关联,如果能预先将主子表都按照主键有序存储,也可以使用有序归并算法有效提速。
esProc SPL 可以把主子表的 EXISTS 转化为有序归并,从而提升计算性能。
下面通过订单表和订单明细表的例子,介绍这种情况的外置提速方法。
先完成数据准备,可以直接使用第四篇生成的 CTX 文件。
例 5.1 对包含 7 号产品的订单,按照客户号分组统计订单个数。
select o.customer_id, count(o.order_id)
from orders o
where o.order_date >= '2024-12-31'
and o.order_date < '2025-01-01'
and exists
(select *
from details d
where d.order_id = o.order_id
and d.product_id=7)
group by o.customer_id;
执行时间 41 秒
SPL 代码 23:

A4 把 7 号产品的订单明细,按照 order_id 有序分组,每组只保留第一个 order_id,这样不用生成分组子集,性能更好。
分组结果在 A5 中和订单表有序归并,再在 A5 中分组统计订单数量。
A3 中游标的最后一个参数是 A2,表示多线程并行时,details 表会跟随 orders 表分段,保证后面两个表有序归并的正确性。
执行时间:0.2 秒
例 5.2 产品号为 6 的订单明细,有多少条在订单表中找不到记录。
select count(d.order_id)
from details d
where d.product_id = 6
and not exists
(select *
from orders o
where o.order_id = d.order_id);
执行时间:16 秒
SPL 代码 24:
A4 中 joinx 的选项 @d,表示用订单表过滤明细表,只保留在订单表中找不到的 order_id。
A5 对 A4 游标计数,就是想要的结果了。
执行时间:0.2 秒
例 5.3 找出明细不止一条的订单,要求订单不包含 9 号产品,按照日期分组统计订单数量。
select o.order_date,count(distinct o.order_id)
from orders o
where
exists (
select 1
from details d
where d.order_id = o.order_id
group by d.order_id
having count(*) > 1
)
and not exists (
select 1
from details d
where d.order_id = o.order_id and d.product_id = 9
)
MYSQL 跑了 5 分钟没出结果。
SPL 代码 25:

A3 把明细表按照 order_id 有序分组。
A4 循环过滤每一组,~ 表示当前组。只保留 order_ id 个数大于 1 且不包含 product_id 为 9 的组。
执行时间:0.9 秒
小结一下性能(单位 - 秒):
请动手练习一下:
1、对包含 8 号产品的订单,按照日期分组统计订单个数。
2、思考:在自己熟悉的数据库中有没有大主子表关联计算 EXISTS?是否可以用有序归并方法提速?