背景:今天對一個20w的表作關聯查詢,建立各類索引,沒有提升執行的效率,使用EXPLAIN檢查,老是提示「Using temporary」全表掃描,這不是我想的。經過度娘,各類百度,是由於DISTINCT使用了全表掃描,如今特別記錄下來。以背查驗。html
參考:
https://www.cnblogs.com/uttu/p/6384541.html
https://blog.csdn.net/songxixi/article/details/8475747
附網上一個同窗的分析,你們能夠參考
須要優化的查詢:使用explain
出現了Using temporary;
有分頁時出現了Using filesort則表示使用不了索引,須要根據下面的技巧來調整語句
rows過多,或者幾乎是全表的記錄數;
key 是 (NULL);
possible_keys 出現過多(待選)索引。
1.使用explain語法,對SQL進行解釋,根據其結果進行調優:
MySQL 表關聯的算法是 Nest Loop Join,是經過驅動表的結果集做爲循環基礎數據,而後一條一條地經過該結果集中的數據做爲過濾條件到下一個表中查詢數據,而後合併結果:
a.EXPLAIN 結果中,第一行出現的表就是驅動表
b.對驅動表能夠直接排序,對非驅動表(的字段排序)須要對循環查詢的合併結果(臨時表)進行排序(Important!),即using temporary;
c. [驅動表] 的定義爲:1)指定了聯接條件時,知足查詢條件的記錄行數少的表爲[驅動表];2)未指定聯接條件時,行數少的表爲[驅動表](Important!)。
d.優化的目標是儘量減小JOIN中Nested Loop的循環次數,以此保證:永遠用小結果集驅動大結果集(Important!)!:A JOIN B,A爲驅動,A中每一行和B進行循環JOIN,看是否知足條件,因此當A爲小結果集時,越快。
e.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解釋語句;
1)若是第一行的驅動表爲a,則效率會很是高,無需優化;
2)不然,由於只能對驅動表字段直接排序的緣故,會出現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,不會起到任何效果node