多步骤复杂 SQL 优化实例

本文通过一个实例讲述了如何优化多步骤的SQL查询,涉及数据表deliver和deliverItem,目标是统计客户完成和未完成的投递行为。通过改进SQL逻辑,减少数据处理的复杂性和提高性能。同时,介绍了SPL语言如何更高效地描述计算过程,降低开发和维护成本。

问题

先看数据:deliver 表是主表,一个客户会发生多次投递行为:

deliverItem 表是从表,一个投递行为有多个投递项,delivered 是投递状态(1 表示未完成,2 表示投递完成):

需求是统计每个客户下,全部完成的投递行为有几次,未完成(只要存在未完成的投递项,就算作未完成)的投递行为有几次。

解答

自然思路的解题步骤:

1、 在deliverItem表里统计每个投递行为下未完成投递的项目数notDelivered;

2、 上一步结果和deliver表连接在一起,得到新的结果集[customer,notDelivered]

3、 按照customer分组,统计每个customer里notDelivered=0(已完成)个数 / notDelivered>0(未完成)个数

SQL:

select r1.customer,r1.complete,r2.notComplete

from

(select customer, count(*) as complete

from

(select d.customer, d2.notDelivered

from deliver d

left join

(select deliverID,count(*) as notDelivered

from deliverItem

where delivered==1

group by deliverID) d2

on d.deliverID=d2.deliverID)

where notDelivered is null

group by customer

) r1

join

(select customer, count(*) as notComplete

from

(select d.customer, d2.notDelivered

from deliver d

left join

(select deliverID,count(*) as notDelivered

from deliverItem

where delivered==1

group by deliverID) d2

on d.deliverID=d2.deliverID)

where notDelivered <> null

group by customer

) r2

on r1.customer=r2.customer

按照开始的自然思路编写SQL的时候,发现会遇到各种困难,通过寻找符合SQL语法的替代思路逐一解决,就得到上面的结果。需要绕行的逻辑复杂时,不同的程序员思维方式不一样,考虑的SQL性能优化方案不同,最终利用各种技巧实现的绕行方案也会千差万别。最终SQL的思路变成了这样:

1、 在deliverItem表里过滤出所有未完成的投递项,按照deliverID分组,统计每个分组未完成项的个数netDlivered;

2、 deliver表通过左连接方式连接第一步的结果集得到新结果集[customer,notDelivered];

3、 按照customer分组,统计出每个客户下全部完成(notDlivered=null)的投递行为的个数complete,得到结果集[customer,commplete];

4、 重复第1步;

5、 重复第2步;

6、 重复第3步,但稍有改动,把notDlivered=null条件变成notDlivered>0,统计出每个客户下未完成的投递行为个数notComplete,得到结果集[customer, notComplete];

7、 两个结果集连接,得到答案[customer,complete,notComplete]。

集算器SPL脚本:

A

1

=connect("mysqlDB")

2

=A1.query(“select * from deliver”)

3

=A1.query(“select * from deliverItem”)

4

=A3.group(deliverID;~.select(delivered==1).len():notDelivered)

5

=A2.switch(deliverID,A4:deliverID)

6

=A5.group(customer;

~.select(deliverID.notDelivered>0).len():notComlete,

~.select(deliverID.notDelivered==0).len():comlete)

7

=A1.close()

A1连接数据库;

A2/A3加载两个表的数据(如果换成excel或csv文本等等数据,也有方便的加载函数);

A4/A5/A6是该查询的功能语句,基本能按照自然思路完成编程;

A4把deliverItem表按deliverID分组,汇总出每个投递行为下未完成投递项的个数notDelivered,包括notDelivered=0的组;

A5把A4结果集和deliver表连接起来,把deliver表的deliverID字段值用switch函数替换成A4结果集里相对应的记录,注意SQL表里无法表达这种嵌套,更无法支持这种嵌套结构带来的便捷计算操作。在下面的运行结果截图里能清楚的看到这种结构;

A6以customer分组,查找notDelivered>0的个数得到未完成投递行为个数notComplete,查找notDelivered=0的个数得到完成投递行为个数complete。

总结

稍微复杂点的查询需求,写SQL就会是个烧脑的过程,除了证明我们人脑很聪明,逻辑思维能力强之外,剩余的就全是缺点,每个人经常用不同于其他人思路的方式绕行到同一个结果上,个性化这么强的编程方式,导致编写SQL、阅读SQL、调试SQL都很困难,维护成本也大大增高。

在程序员编程描述计算这件事上,集算器 SPL 语言通过创新的数学理论模型《离散数据集》,大大改善《关系代数》(SQL背后的数学模型)在描述计算时的困难。简单的说是对有序计算更彻底的集合运算提倡分步等多方面创新,达到提高程序员描述计算效率的目的。而提高描述计算效率的效果,除了降低开发、维护成本,还有个副作用是提高性能,因为高性能算法的程序也更容易被编写出来了。

这里有更多详细的技术文章:

SPL 语言

SQL 优化

快速上手试试:

下载集算器

如何免费使用润乾集算器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值