多步驟複雜 SQL 優化思路

原文鏈接:http://c.raqsoft.com.cn/article/1576562814244?r=CGQ

原文鏈接可以查看更多更詳細的sql優化示例

問題

先看數據:deliver 表是主表,一個客戶會發生多次投遞行爲:

2png

deliverItem 表是從表,一個投遞行爲有多個投遞項,delivered 是投遞狀態(1 表示未完成,2 表示投遞完成):

3png

需求是統計每個客戶下,全部完成的投遞行爲有幾次,未完成(只要存在未完成的投遞項,就算作未完成)的投遞行爲有幾次。

解答

自然思路的解題步驟:

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。

1png

總結

稍微複雜點的查詢需求,寫SQL就會是個燒腦的過程,除了證明我們人腦很聰明,邏輯思維能力強之外,剩餘的就全是缺點,每個人經常用不同於其他人思路的方式繞行到同一個結果上,個性化這麼強的編程方式,導致編寫SQL、閱讀SQL、調試SQL都很困難,維護成本也大大增高。

在程序員編程描述計算這件事上,集算器 SPL 語言通過創新的數學理論模型《離散數據集》,大大改善《關係代數》(SQL背後的數學模型)在描述計算時的困難。簡單的說是對有序計算更徹底的集合運算提倡分步等多方面創新,達到提高程序員描述計算效率的目的。而提高描述計算效率的效果,除了降低開發、維護成本,還有個副作用是提高性能,因爲高性能算法的程序也更容易被編寫出來了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章