首頁>Club>
10
回覆列表
  • 1 # 遠哥說事

    我來講一下這個問題吧:題主說的查詢應該是這樣吧:select * from a where id in (select id from b );

    對於這條sql語句它的執行計劃其實並不是先查詢出b表的所有id,然後再與a表的id進行比較。mysql會把in子查詢轉換成exists相關子查詢,所以它實際等同於這條sql語句:select * from a where exists(select * from b where b.id=a.id );

    而exists相關子查詢的執行原理是: 迴圈取出a表的每一條記錄與b表進行比較,比較的條件是a.id=b.id . 看a表的每條記錄的id是否在b表存在,如果存在就行返回a表的這條記錄。

    exists查詢有什麼弊端?由exists執行原理可知,a表(外表)使用不了索引,必須全表掃描,因為是拿a表的資料到b表查。而且必須得使用a表的資料到b表中查(外表到裡表中),順序是固定死的。

    如何最佳化?建索引。但是由上面分析可知,要建索引只能在b表的id欄位建,不能在a表的id上,mysql利用不上。

    這樣最佳化夠了嗎?還差一些。由於exists查詢它的執行計劃只能拿著a表的資料到b表查(外表到裡表中),雖然可以在b表的id欄位建索引來提高查詢效率。但是並不能反過來拿著b表的資料到a表查,exists子查詢的查詢順序是固定死的。

    為什麼要反過來?因為首先可以肯定的是反過來的結果也是一樣的。這樣就又引出了一個更細緻的疑問:在雙方兩個表的id欄位上都建有索引時,到底是a表查b表的效率高,還是b表查a表的效率高?

    該如何進一步最佳化?把查詢修改成inner join連線查詢:select * from a inner join b on a.id=b.id; (但是僅此還不夠,接著往下看)

    為什麼不用left join 和 right join?這時候表之間的連線的順序就被固定住了,

    比如左連線就是必須先查左表全表掃描,然後一條一條的到另外表去查詢,右連線同理。仍然不是最好的選擇。

    為什麼使用inner join就可以?inner join中的兩張表,如: a inner join b,但實際執行的順序是跟寫法的順序沒有半毛錢關係的,最終執行也可能會是b連線a,順序不是固定死的。如果on條件欄位有索引的情況下,同樣可以使用上索引。

    那我們又怎麼能知道a和b什麼樣的執行順序效率更高?答:你不知道,我也不知道。誰知道?mysql自己知道。讓mysql自己去判斷(查詢最佳化器)。具體表的連線順序和使用索引情況,mysql查詢最佳化器會對每種情況做出成本評估,最終選擇最優的那個做為執行計劃。

    在inner join的連線中,mysql會自己評估使用a表查b表的效率高還是b表查a表高,如果兩個表都建有索引的情況下,mysql同樣會評估使用a表條件欄位上的索引效率高還是b表的。

    而我們要做的就是:把兩個表的連線條件的兩個欄位都各自建立上索引,然後explain 一下,檢視執行計劃,看mysql到底利用了哪個索引,最後再把沒有使用索引的表的欄位索引給去掉就行了。

  • 中秋節和大豐收的關聯?
  • 鮮羊皮怎麼熟?