了解MySQL聯表查詢中的驅動表,優化查詢,以小表驅動大表


一、為什么要用小表驅動大表

1、驅動表的定義

當進行多表連接查詢時, [驅動表] 的定義為:

1)指定了聯接條件時,滿足查詢條件的記錄行數少的表為[驅動表]

2)未指定聯接條件時,行數少的表為[驅動表](Important!)

忠告:如果你搞不清楚該讓誰做驅動表、誰 join 誰,請讓 MySQL 運行時自行判斷

既然“未指定聯接條件時,行數少的表為[驅動表]”了,而且你也對自己寫出的復雜的 Nested Loop Join 不太有把握(如下面的實例所示),就別指定誰 left/right join 誰了,請交給 MySQL優化器 運行時決定吧。

如果您對自己特別有信心


2、mysql關聯查詢的概念:

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


例: user表10000條數據,class表20條數據

select * from user u left join class c u.userid=c.userid

這樣則需要用user表循環10000次才能查詢出來,而如果用class表驅動user表則只需要循環20次就能查詢出來

例:

select * from class c left join user u c.userid=u.userid


小結果集驅動大結果集

de.cel 在2012年總結說,不管是你,還是 MySQL,優化的目標是盡可能減少JOIN中Nested Loop的循環次數。

以此保證:永遠用小結果集驅動大結果集(Important)!


二、優化聯表查詢

優化第一步之:根據驅動表的字段排序


left join不變,干嘛要根據非驅動表的字段排序呢?我們前面說過“對驅動表可以直接排序,對非驅動表(的字段排序)需要對循環查詢的合並結果(臨時表)進行排序!”的。

explain

SELECT mb.id……

FROM mb LEFT JOIN mbei ON mb.id=mbei.mb_id INNER JOINu ON mb.uid=u.uid  

WHERE 1=1  

ORDER BY mb.id DESC

limit 0,10

也滿足業務場景,做到了rows最小:


優化第二步:去除所有JOIN,讓MySQL自行決定,explain第一張表就是驅動表,數據量比其它兩張表都要小!

explain
SELECT mb.id……
FROM mb,mbei,u
WHERE
mb.id=mbei.mb_id
and mb.uid=u.user_id
order by mbei.apply_time desc
limit 0,10

立竿見影,驅動表一樣是小表 mbei:

id select_type table   type    possible_keys      key          key_len  ref                rows    Extra
1 SIMPLE mbei ALL mb_id (NULL) (NULL) (NULL) 13388 Using filesort
1 SIMPLE mb eq_ref PRIMARY,userid PRIMARY 4 mbei.mb_id 1
1 SIMPLE u eq_ref PRIMARY PRIMARY 4 mb.uid 1 Using index


三、總結

1、不要過於相信你的運氣!

2、不要相信你的開發環境里SQL的執行速度!

3、請拿起 explain 武器,如果你看到以下現象,請優化:

1)出現了Using temporary

2)rows過多,或者幾乎是全表的記錄數

3)key 是 (NULL)

4)possible_keys 出現過多(待選)索引







免責聲明!

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



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