天天看點

驅動表

同樣的SQL,不同的表做驅動表可能會導緻執行的不同。例如:

1) 主表為lesson:
EXPLAIN SELECT l.* 
FROM lesson l 
INNER JOIN lesson_collect lc ON l.lesson_id=lc.lesson_id 
WHERE lc.account_id='...' 
ORDER BY l.`create_time` DESC\G;           
驅動表
2) 主表為lesson_collect
EXPLAIN SELECT l.* 
FROM lesson_collect lc 
INNER JOIN lesson l ON lc.lesson_id=l.lesson_id 
WHERE lc.account_id='...' 
ORDER BY l.`create_time` DESC\G;           
驅動表

同樣的語句, lc做主表能夠導緻兩張表都使用索引,l做索引隻能使用一個索引;lc做主表使用了temporary和filesort,而l做主表使用了filesort。

驅動表

MySQL優化器處理多表連接配接時首先要确定以誰為驅動表,也就是說以哪個表為基準,一般情況下,哪個表的結果集小,就以哪個表為驅動表。

MySQL 表關聯的算法是 Next LOOP Join,是通過驅動表的結果集作為循環基礎資料,然後一條一條地通過該結果集中的資料作為過濾條件到下一個表中查詢資料,然後合并結果。

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

1) 指定了聯接條件時,滿足查詢條件的記錄行數少的表為驅動表;
2) 未指定聯接條件時,行數少的表為驅動表;
3) LEFT JOIN和straight_join中, 最左表為驅動表;
4) INNER JOIN中,MySQL優化器自動選擇最小表作為驅動表。           

優化的目标是盡可能減少JOIN中Nested Loop的循環次數, 使用小結果集驅動大結果集。

是以,有時候,同一SQL語句,inner join會比left join要快。原因就是inner join可以由mysql自己選擇驅動表,而left join很可能被程式員定義為慢表為驅動表。

驅動表造成的問題

mysql自動選取驅動表也不一定是真正的最優方案。當SQL中沒有order by時,MySQL優化器選擇的驅動表一般沒有問題。可當表需要字段來排序,例如create_time,如果排序字段不在驅動表裡,就不可避免的出現

「Using filesort」

「Using temporary」

是以,要盡可能的保證排序字段在驅動表中,left join和straight_join可以強制指定連接配接順序。

有時可能遇到這種問題:原本運作良好的查詢語句,過了一段時間後,突然變得很糟糕。有可能是因為資料分布情況發生了變化,進而導緻MySQL優化器對驅動表的選擇發生了變化,進而出現索引失效的情況。