不要求每一個人必定理解 聯表查詢(join/left join/inner join等)時的mysql運算過程;mysql
不要求每一個人必定知道線上(如今或將來)哪張表數據量大,哪張表數據量小;算法
但要常常使用explain查看執行計劃,這是一種美德!sql
下面兩個查詢,它們只差了一個order by,效果卻迥然不一樣。app
第一個查詢:oop
EXPLAIN extended SELECT ads.id FROM ads, city WHERE city.city_id = 8005 AND ads.status = 'online' AND city.ads_id=ads.id ORDER BY ads.id desc
執行計劃爲:優化
id select_type table type possible_keys key key_len ref rows filtered Extra ------ ----------- ------ ------ -------------- ------- ------- -------------------- ------ -------- ------------------------------- 1 SIMPLE city ref ads_id,city_id city_id 4 const 2838 100.00 Using temporary; Using filesort 1 SIMPLE ads eq_ref PRIMARY PRIMARY 4 city.ads_id 1 100.00 Using where
第二個查詢:ui
EXPLAIN extended SELECT ads.id FROM ads,city WHERE city.city_id =8005 AND ads.status = 'online' AND city.ads_id=ads.id ORDER BY city.ads_id desc
執行計劃裏沒有了using temporary:spa
id select_type table type possible_keys key key_len ref rows filtered Extra ------ ----------- ------ ------ -------------- ------- ------- -------------------- ------ -------- --------------------------- 1 SIMPLE city ref ads_id,city_id city_id 4 const 2838 100.00 Using where; Using filesort 1 SIMPLE ads eq_ref PRIMARY PRIMARY 4 city.ads_id 1 100.00 Using where
忠告:若是你搞不清楚該讓誰作驅動表、誰 join 誰,請讓 MySQL 運行時自行判斷code
先了解一下 mb 表有 千萬級記錄,mbei 表要少得多。慢查實例以下:blog
explain SELECT mb.id, …… FROMmb LEFT JOIN mbei ON mb.id=mbei.mb_id INNER JOIN u ON mb.uid=u.uid WHERE 1=1 ORDER BY mbei.apply_time DESC limit 0,10
id select_type table type possible_keys key key_len ref rows Extra ------ ----------- ------ ------ -------------- -------------- ------- ------------------- ------- -------------------------------------------- 1 SIMPLE mb index userid userid 4 (NULL) 6060455 Using index; Using temporary; Using filesort 1 SIMPLE mbei eq_ref mb_id mb_id 4 mb.id 1 1 SIMPLE u eq_ref PRIMARY PRIMARY 4 mb.uid 1 Using index
因爲動用了「LEFT JOIN」,因此攻城獅已經指定了驅動表,雖然這張驅動表的結果集記錄數達到百萬級!
幹嗎要 left join 啊?直接 join!
explain SELECT mb.id…… FROM mb JOIN mbei ON mb.id=mbei.mb_id INNER JOIN u ON mb.uid=u.uid WHERE 1=1 ORDER BY mbei.apply_time DESC limit 0,10
立竿見影,驅動表馬上變爲小表 mbei 了, Using temporary 消失了,影響行數少多了:
id select_type table type possible_keys key key_len ref rows Extra ------ ----------- ------ ------ -------------- ------- ------- ---------------------------- ------ -------------- 1 SIMPLE mbei ALL mb_id (NULL) (NULL) (NULL) 13383 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
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最小:
id select_type table type possible_keys key key_len ref rows Extra ------ ----------- ------ ------ -------------- -------------- ------- ------------------- ------ ----------- 1 SIMPLE mb index userid PRIMARY 4 (NULL) 10 1 SIMPLE mbei eq_ref mb_id mb_id 4 mb.id 1 Using index 1 SIMPLE u eq_ref PRIMARY PRIMARY 4 mb.uid 1 Using index
寫這麼多密密麻麻的 left join/inner join 很開心嗎?
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