大家好,我是知數堂SQL 優化班老師 網名:騎龜的兔子
在之前的的系列文章中,有意思的SQL(3) 行轉列,列轉行和複制
已經給大家介紹了,行轉列,列轉行,複制等方法。
在這篇文章中,對其進行更深一層的應用。
需求如下,
有一個表如下圖所示
現在有個需求是,我在畫面輸入
'10004,22744,24007' 要求傳回對應的三行資料
當然有很多種解決方案,一類是,在前端或者server端 用語言把輸入值分開,
還有一種是在資料庫端,本文介紹的是在資料庫端的方法,
當然還有 最簡單方案如下
這種方案,也可以解決輸入值有空格的情況
那這種方案的問題在哪呢?
先看下,這個表中是有索引的如下
運作了,下面的SQL 從執行計劃中,可看出,走全表掃描了
也就是說表越大,有可能越慢!
寫SQL 有幾個階段,第一個階段是為了熟悉各種文法,和實作各種需求階段
第二個階段是,寫出,更符合資料庫特點,符合優化思路的SQL
上面的SQL 就是滿足了需求,但是不符合優化。
如果寫成如下
就可以有能滿足需求,有能達到優化效果的SQL!
那現在的問題是,怎麼把 '10004','22744','24007' 一行資料的變成3行資料的問題!
這樣總算,文章又回到,本文開篇,沒跑題~~
根據上篇文章,我們想把一行資料變成多行,我們需要複制
這裡我用到了MySQL 8.0 開始支援的with 語句,
不支援的可以用臨時表代替。
其中 num 是為了複制而弄的中間表,可以了解為,我們中學的幾何題中,為了解決問題畫的輔助線~~。
上面的SQL 已經達到複制效果了,但是顯然,複制的有點多了,我們隻需要3行資料,但複制了5行,顯然不行,我們觀察下,結果發現我們如果複制的行數是逗号的個數+1 就可以了!
那怎麼表達呢,我們用原來的length-去掉逗号後length +1 就可以
從上圖所示,可以看出,這樣就複制了我們想要的行數。
現在就剩下,怎麼截取的問題,我們想要的是第一行截取第一個,第二行第二個,第n行第n個 。。。
MySQL 8.0給我們提供了regexp_substr這樣的強大的函數,專門解決這樣的問題
當然還有别的解決方案,為了代碼的簡單,我就用了這個函數
這樣我們就解決了,行轉列的問題,剩下的是把這部分帶到原來的SQL 中,
執行計劃如下,執行計劃稍微有點複雜,初學者比較難懂
下面是運作結果,還是符合需求的
為了,給大家一個直覺的感覺,我用大表salaries 表替換了原來的dept_emp表
然後運作SQL如下 運作了3.8 秒 !
用修改之後代碼 行數太多,我把資料删了保留時間如下 0.01秒
用倍數的話。。。
本文,通過一個簡單案例,給大家講述了,SQL開發過程中的幾個方法和優化思路,我們不僅僅開發過程中想到怎麼解決需求,若果想進一步,就需要考慮性能問題
謝謝大家~
我是知數堂SQL 優化班老師~ ^^
如有關于SQL優化方面疑問和一起交流的請加 并且 @兔子@知數堂SQL優化