問題
通過「SHOW FULL PROCESSLIST」語句很容易就能查到問題SQL,如下:
| SELECT post.*FROM postINNER JOIN post_tag ON post.id = post_tag.post_idWHERE post.status = 1 AND post_tag.tag_id = 123ORDER BY post.created DESCLIMIT 100 |
說明:因為post和tag是多對多的關系,所以存在一個關聯表post_tag。
試著用EXPLAIN查詢一下SQL執行計劃(篇幅所限,結果有刪減):
| +----------+---------+-------+-----------------------------+| table | key | rows | Extra |+----------+---------+-------+-----------------------------+| post_tag | tag_id | 71220 | Using where; Using filesort || post | PRIMARY | 1 | Using where |+----------+---------+-------+-----------------------------+ |
下面給出優化后的SQL,唯一的變化就是把連接方式改成了「STRAIGHT_JOIN」:
| SELECT post.*FROM postSTRAIGHT_JOIN post_tag ON post.id = post_tag.post_idWHERE post.status = 1 AND post_tag.tag_id = 123ORDER BY post.created DESCLIMIT 100 |
試著用EXPLAIN查詢一下SQL執行計劃(篇幅所限,結果有刪減):
| +----------+----------------+--------+-------------+| table | key | rows | Extra |+----------+----------------+--------+-------------+| post | status_created | 119340 | Using where || post_tag | post_id | 1 | Using where |+----------+----------------+--------+-------------+ |
對比優化前后兩次EXPLAIN的結果來看,優化后的SQL雖然「rows」更大了,但是沒有了「Using filesort」,綜合來看,性能依然得到了提升。
解釋
對第一條SQL而言,為什么MySQL優化器選擇了一個耗時的執行方案?對第二條SQL而言,為什么把連接方式改成STRAIGHT_JOIN之后就提升了性能?
這一切還得從MySQL對多表連接的處理方式說起,首先要確定以誰為驅動表,也就是說以哪個表為基準,在處理此類問題時,MySQL優化器采用了簡單粗暴的解決方法:哪個表的結果集小,就以哪個表為驅動表,通常這都是最佳選擇。
說明:在EXPLAIN結果中,第一行出現的表就是驅動表。
繼續post連接post_tag的例子,MySQL優化器有如下兩個選擇,分別是:
顯而易見,post_tag過濾的結果集更小,所以MySQL優化器選擇它作為驅動表,可悲催的是我們還需要以post表中的created字段來排序,也就是說排序字段不在驅動表里,于是乎不可避免的出現了「Using filesort」,從而導致慢查詢。
新聞熱點
疑難解答