在實際生產中,關于 join 語句使用的問題,一般會集中在以下兩類:
我們 DBA 不讓使用 join,使用 join 有什么問題呢?
如果有兩個大小不同的表做 join,應該用哪個表做驅動表呢?
第一個問題:能不能使用 join 語句?
如果可以使用 Index Nested-Loop Join 算法,也就是說可以用上被驅動表上的索引,其實是沒問題的;
如果使用 Block Nested-Loop Join 算法,掃描行數(shù)就會過多。尤其是在大表上的 join 操作,這樣可能要掃描被驅動表很多次,會占用大量的系統(tǒng)資源。所以這種 join 盡量不要用。
所以你在判斷要不要使用 join 語句時,就是看 explain 結果里面,Extra 字段里面有沒有出現(xiàn)“Block Nested Loop”字樣。
第二個問題是:如果要使用 join,應該選擇大表做驅動表還是選擇小表做驅動表?
如果是 Index Nested-Loop Join 算法,應該選擇小表做驅動表;
如果是 Block Nested-Loop Join 算法:
在 join_buffer_size 足夠大的時候,是一樣的;
在 join_buffer_size 不夠大的時候(這種情況更常見),應該選擇小表做驅動表。
所以,這個問題的結論就是,總是應該使用小表做驅動表。
案例:
1)優(yōu)化前的sql語句以channels_news為第一個關聯(lián)表,找到161590條記錄;
2)優(yōu)化后的sql語句以news表為第一關聯(lián)表,找到255440條記錄,比第一條sql語句查找多了9W多條。因此,優(yōu)化前的sql語句的關聯(lián)順序是MySQL優(yōu)化器的選擇,可以讓查詢進行更小的嵌套循環(huán)和回溯操作。MySQL通過選擇合適的關聯(lián)順序來讓查詢執(zhí)行的成本盡可能低,重新定義關聯(lián)的順序是優(yōu)化器很重要的一部分功能。不過有時候,優(yōu)化器給出的并不是最優(yōu)的關聯(lián)順序。這時可以使用STRAIGHT_JOIN關鍵字重寫查詢,讓優(yōu)化器按照你認為的最優(yōu)關聯(lián)順序執(zhí)行。
造成這次sql語句查詢耗時5s的原因是,sql語句order by的字段不在mysql的優(yōu)化器選在驅動表上,所以導致這次關聯(lián)查詢排序字段上的索引沒有被使用。因此,通過使用STRAIGHT_JOIN來強制制定關聯(lián)查詢的表順序,以達到優(yōu)化的目的。但是,有時候我們人為地指定順序不一定比mysql的優(yōu)化引擎準確,所以在使用STRAIGHT_JOIN的時候三思而后行