寫在前面的話:
?? 不要求每個人一定理解 聯表查詢(join/left join/inner join等)時的mysql運算過程;
???不要求每個人一定知道線上(現在或未來)哪張表數據量大,哪張表數據量小;
????但把mysql客戶端(如SQLyog,如HeidiSQL)放在桌面上,時不時拿出來 explain 一把,這是一種美德!
在實例講解之前,我們先回顧一下聯表查詢的基礎知識。
——聯表查詢的基礎知識——
引子:為什么第一個查詢using temporary,第二個查詢不用臨時表呢?
下面兩個查詢,它們只差了一個order by,效果卻迥然不同。
第一個查詢:
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???????????????????
第二個查詢:
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
------? -----------? ------? ------? --------------? -------? -------? --------------------? ------? --------? ---------------------------
???? 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???????????????
1)指定了聯接條件時,滿足查詢條件的記錄行數少的表為[驅動表];
2)未指定聯接條件時,行數少的表為[驅動表](Important!)。
永遠用小結果集驅動大結果集(Important!)!
——實例講解——
explainSELECT mb.id, ……FROMmb?LEFT JOIN mbei ON mb.id=mbei.mb_id?INNER JOINu ON mb.uid=u.uid ?WHERE 1=1 ?ORDER BY mbei.apply_time DESClimit 0,10
------? -----------? ------? ------? --------------? --------------? -------? -------------------? -------? --------------------------------------------
???? 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????????????????????????????????
explainSELECT mb.id……FROM mb?JOIN mbei ON mb.id=mbei.mb_id?INNER JOINu ON mb.uid=u.uid ?WHERE 1=1 ?ORDER BY mbei.apply_time DESClimit 0,10
------? -----------? ------? ------? --------------? -------? -------? ----------------------------? ------? --------------
???? 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??
優化第一步之分支1:根據驅動表的字段排序,好嗎?
explainSELECT 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 DESClimit 0,10
------? -----------? ------? ------? --------------? --------------? -------? -------------------? ------? -----------
???? 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
優化第二步:去除所有JOIN,讓MySQL自行決定!
explainFROM mb,mbei,u? ?SELECT mb.id……
WHERE
?? ?mb.id=mbei.mb_id
?? ?and mb.uid=u.user_id
order by mbei.apply_time desc
limit 0,10
------? -----------? ------? ------? --------------? -------? -------? ----------------------------? ------? --------------
???? 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??
最后的總結:
不要過于相信你的運氣!不要相信你的開發環境里SQL的執行速度!請拿起 explain 武器,如果你看到以下現象,請優化:
- 出現了Using temporary;
- rows過多,或者幾乎是全表的記錄數;
- key 是 (NULL);
- possible_keys 出現過多(待選)索引。
?記住,explain 是一種美德!
