MySQL百萬級、千萬級數據多表關聯SQL語句調優


本文不涉及復雜的底層數據結構,通過explain解釋SQL,並根據可能出現的情況,來做具體的優化,使百萬級、千萬級數據表關聯查詢第一頁結果能在2秒內完成(真實業務告警系統優化結果)。

希望讀者能夠理解SQL的執行過程,並根據過程優化,走上自己的"成金之路"

需要優化的查詢:

使用explain
出現了Using temporary;

有分頁時出現了Using filesort則表示使用不了索引,需要根據下面的技巧來調整語句

  • rows過多,或者幾乎是全表的記錄數;

  • key 是 (NULL);

  • possible_keys 出現過多(待選)索引。

1.使用explain語法,對SQL進行解釋,根據其結果進行調優:

MySQL 表關聯的算法是 Nest Loop Join,是通過驅動表的結果集作為循環基礎數據,然后一條一條地通過該結果集中的數據作為過濾條件到下一個表中查詢數據,然后合並結果:

  • EXPLAIN 結果中,第一行出現的表就是驅動表

  • 對驅動表可以直接排序,對非驅動表(的字段排序)需要對循環查詢的合並結果(臨時表)進行排序(Important!),即using temporary;

  • [驅動表] 的定義為:1)指定了聯接條件時,滿足查詢條件的記錄行數少的表為[驅動表];2)未指定聯接條件時,行數少的表為[驅動表](Important!)。

  • 優化的目標是盡可能減少JOIN中Nested Loop的循環次數,以此保證:永遠用小結果集驅動大結果集(Important!)!:A JOIN B,A為驅動,A中每一行和B進行循環JOIN,看是否滿足條件,所以當A為小結果集時,越快。

  • NestedLoopJoin實際上就是通過驅動表的結果集作為循環基礎數據,然后一條一條的通過該結果集中的數據作為過濾條件到下一個表中查詢數據,然后合並結果。如果還有第三個參與Join,則再通過前兩個表的Join結果集作為循環基礎數據,再一次通過循環查詢條件到第三個表中查詢數據,如此往復

2.兩表JOIN優化:

a.當無order by條件時,根據實際情況,使用left/right/inner join即可,根據explain優化 ;

b.當有order by條件時,如select * from a inner join b where 1=1 and other condition order by a.col;使用explain解釋語句;

  • 如果第一行的驅動表為a,則效率會非常高,無需優化;

  • 否則,因為只能對驅動表字段直接排序的緣故,會出現using temporary,所以此時需要使用STRAIGHT_JOIN明確a為驅動表,來達到使用a.col上index的優化目的;或者使用left join且Where條件中不含b的過濾條件,此時的結果集為a的全集,而STRAIGHT_JOIN為inner join且使用a作為驅動表

3.多表JOIN優化:

a.無order by條件時,根據實際情況,使用left/right/inner join即可,根據explain優化;

b.有order by a.col條件時,所有join必須為left join,且每個join字段都創建索引,同時where條件中只能有a表的條件,即將其它表的數據關聯到a中形成一張大表,再對a的全集進行過濾;

如果不能全使用left join,則需靈活使用STRAIGHT_JOIN及其它技巧,以時間排序為例:

1)數據入庫按照平台時間入庫,自然a的數據都按時間有序;

SELECT
    c.*, r.HYPERVISOR_HOST_NAME hostname,
    r.HOST_IP
FROM
    trust_monitor c STRAIGHT_JOIN res_node r ON c.res_node_id = r.ID STRAIGHT_JOIN am_assets a ON r.ASSET_ID = a.ID
AND a. STATUS = 58 STRAIGHT_JOIN se_role s ON a.DEPT_FLAG = s.ROLE_ORG
AND s.ROLE_ID IN (32, 33, 36, 41)
WHERE
    c. STATUS = 58
AND c.changed_type = 79
LIMIT 1,
 10;

  兩者結果一致

SELECT
    c.*, r.HYPERVISOR_HOST_NAME hostname,
    r.HOST_IP
FROM
    trust_monitor c
INNER JOIN res_node r ON c.res_node_id = r.ID
INNER JOIN am_assets a ON r.ASSET_ID = a.ID
AND a. STATUS = 58
INNER JOIN se_role s ON a.DEPT_FLAG = s.ROLE_ORG
AND s.ROLE_ID IN (32, 33, 36, 41)
WHERE
    c. STATUS = 58
AND c.changed_type = 79
ORDER BY
    c.changed_time
LIMIT 1,
 10;

4.誤區:

a.視圖只是屏蔽或者高效集合多表數據的一種方法,視圖與表JOIN,不會起到任何效果

來源: 程序員DD, 程序員小灰, macrozheng


免責聲明!

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



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