mysql數據庫多表關聯查詢的慢SQL優化


  工作中我們經常用到多個left join去關聯其他表查詢結果,但是隨着數據量的增加,一個表的數據達到百萬級別后,這種普通的left join查詢將非常的耗時。

舉個例子:

    現在porder表有 1000W數據,其他關聯的表數據都很少,因為條件的限制 必須要關聯3個表,正常的邏輯就是這樣寫,但是我們在數據庫執行的時候會發現這樣的SQL 非常耗時,

  而且此時才 limit 800  這樣的SQL怎么能讓用戶受得了呢?

        select p.*,b.supplier,t.type,c.org   from porder p
        left JOIN brand b on p.supplier = b.supplier_id and b.mark = 0
        left JOIN purchase c on p.org = c.id and c.mark = 0
        left JOIN type t on c.category = t.type_id and t.mark = 0
        WHERE p.nark = 0 ORDER BY p.id desc limit 800,500;

  通過查詢SQL優化方面的知識,發現一種比較好的優化方案:

        select p.*,b.supplier,t.type,c.org from
        (select po.id from porder po where po.mark = 0 order by po.id desc limit 800000,500) a
        inner join porder p on a.id = p.id and p.mark = 0
        left JOIN brand b on p.supplier = b.supplier_id and b.mark = 0
        left JOIN purchase c on p.org = c.id and c.mark = 0
        left JOIN type t on c.category = t.type_id and t.mark = 0;

  我們可以先將數據量最大表的滿足條件的ID查詢出來,創建臨時表,再用這個臨時表去關聯這個表本身以及其他表。limit80W 也就1S時間。

SQL分析:

  我們可以使用 explain 查看上面2種SQL的執行計划。第一種SQL的執行計划中 通過 row 和extra 都可以看出 非常差,row幾乎為全部掃描。

  優化后的SQL通過 row 和extra 都可以看出都是很好的狀態,row的數據是第一種的 1%。相當於提升了 100倍。

  執行計划中的id列的數值越大,執行權就越高。id列的值相等的,就從上之下依次執行。明白了這一點,我們就可以再分析SQL了。

  數據庫先執行了 select po.id from porder po where po.mark = 0 order by po.id desc limit 800000,500 這段SQL,將查詢出的有效id(滿足條件的id)放在了臨時表a中,

  然后表a 再與其他的表匹配查詢。

  (注:優先執行的SQL 不參與 后面的表匹配。這里要理解,不然單獨看執行計划,你會納悶為何row列上 a表 中數值小,而 id列為2的表(po) row列的數值也很大。

  你也可以拆分SQL。優先執行的SQL 單獨拿出來執行,將查詢到的結果當作查詢條件,傳給普通的 left join 中的where條件里面 即 in(), in的里面不要寫SQL查詢,必須是明確的數值!)

我只是提供方法,具體的原理,大家可以上網查一查。數據庫有一種叫 驅動表的概念,大家可以了解下。或許對於理解這種方法更方便!

  注:這個優化后的SQL在執行 limit1000000,**  的時候效率也就下降了,大概4S鍾以上。所以這個SQL也是有極限的,對於分頁查詢等等,如果數據量超過100W 要注意!

希望有大神,能在SQL上能有更高的突破,有方法的,希望大家一起分享,一起學習。謝謝~

  補:為了應對超過百萬級別的查詢,或者導出,SQL優化暫時沒有好的辦法,但是我們可以在傳參上做文章。

比如分頁查詢時,每頁展示20條數據,首頁查詢時,我們可以得到首頁最后一條數據的ID (起名:lastId)(按ID排序,降序),當點擊第2頁時,我們可以將 lastId 作為參數傳入分頁查詢的SQL中。

這樣分頁時就加上了一個條件 就是 ID<lastId (按ID排序,降序),limit也可以優化成   limit 20, 這樣優化后,因為limit 不再是 limit xxx,20 ,這樣數據庫在掃描滿足條件的數據時,就會從此ID往后掃描,

且掃描到滿足條件的20條后,就不會再多掃描,大大減少了掃描的數據量,自然也就提升了效率。

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM