一、為什么要用小表驅動大表
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 出現過多(待選)索引