重慶分公司,新征程啟航
為企業提供網站建設、域名注冊、服務器等服務
為企業提供網站建設、域名注冊、服務器等服務
首先,MySql join連接可以連接兩張或更多的數據表,但是并沒有誰是“驅動表”之說。
創新互聯主要從事成都網站制作、成都網站設計、網頁設計、企業做網站、公司建網站等業務。立足成都服務柳州,10余年網站建設經驗,價格優惠、服務專業,歡迎來電咨詢建站服務:18980820575
Join分為"inner join"內連接和"outer join"外連接兩種形式,外連接還可以進一步分為左連接和右連接。
內連接(inner join)只輸出被連接的表它們的關聯字段擁有交集的那些記錄行,沒交集的記錄行將被剔除掉。
外連接(left join左連接/right join右連接):
"left join" 輸出左表所有的記錄行和右表之間關聯字段擁有交集的記錄行,對于右表找不到對應記錄行的,數據庫引擎會將空值Null賦值到右表的各個字段里。
"right join"的情況則于"left join" 剛好相反。
"inner join"——只輸出表之間存在交集的那些記錄行;
"left join" ——輸出左表所有的記錄行以及右表與之有交集的記錄行,右表找不到對應
記錄的,數據庫引擎則將Null賦值到右表的各個字段;
"right join"——輸出右表所有的記錄行以及左表與之有交集的記錄行,左表找不到對應
記錄的,數據庫引擎則將Null賦值到左表的各個字段;
=========================總結===========================
1.開啟慢查詢日志,設置閥值,比如超過5秒就是慢SQL,并把它抓取出來。
2.explain+慢SQL 分析
3.show profile 查詢SQL在MySQL服務器里面的執行細節和聲明周期。
眾所周知, MySQL的驅動表與被驅動表是優化器自動優化選擇的結果 (與表連接的前后順序等無關),我們可以用explain執行計劃來知曉:
如上所示,前面一行t1是驅動表,后面一行t2是被驅動表。那么驅動表與被驅動表的選擇是否有規律可循呢?下面是百度搜索兩個主流的博文對驅動表與被驅動表的闡釋:
1. MySQL連接查詢驅動表被驅動表以及性能優化 - 阿偉~ - 博客園 博文A 主要結論:
2. mysql驅動表與被驅動表及join優化_java小小小黑的博客-CSDN博客_mysql驅動表和被驅動表 博文B 其主要結論:
兩個帖子的結論是都差不多,而且還給出了例子來佐證。那么網上的結論是否權威?是否有普遍性?是否存在缺陷?
讓我們來一起打破砂鍋問到底。下面有兩張表結構一模一樣的表t1,t2:其中t1 100條數據,t2 1000條數據;t1(t2)結構如下:
按照上面博文的結論,left join左邊是t2表,應該是驅動表。我們查看下結果:
與 博文B 中觀點1相違背(同理觀點2也違背),與實際不符,但究竟這是為什么呢?
下面發一張MySQL的執行過程(來源于《MySQL實戰45講》中01講【一條SQL查詢語句是如何執行的】)
so die si ne,原來sql執行的過程是這樣呀。等等,不對,這跟剛才SQL又有什么關系,上面left join中t2表還是左邊的呀。
我們知道MySQL高版本的性能越來越好,它是不斷進行優化迭代的。遠古的mysql版本可能還需要人工把小表放在前面,大表放在后面等這些需要人工調優的經驗早就已經被解決了。也就是說我們寫的語句,MySQL為了追求更好的效率,它在執行器執行前已經幫我們優化了。那么實際優化后的sql如何查看呢?用show warning命令:
其中Message就是優化后實際執行的sql語句,格式化后如下:
優化后left join左連接變成了內連接(inner) join。所以用優化后的sql看,表t1是小表所以作為驅動表,與實際結果相符。
left join 竟然優化成了join,太神奇了,但這是為什么呢?原因在于mysql中null與任何值做等值或者不等值比較的時候都是null,即使是select null=null 也是null。這樣where 條件t1.a=t2.a查詢條件不會包含t2.a為NULL的行,實際效果其實跟join一樣,被優化器智能的優化了。
我們直接看執行計劃看實際結果吧:
結果顯示t2是驅動表,t1是被驅動表。t2是1000條數據按理說是大表應該是被驅動表,與 博文A , 博文B 的結論又不一致了。
《MySQL實戰45講》中34講【到底可不可以使用join】已經講的很透徹了,很深入了,我就不在這里獻丑了。啰嗦幾句大概就是驅動表是全表掃描不走索引,所以選被驅動表t1可以走索引,不會全表掃描,減少IO次數,性能高。里面對大表小表的總結,簡直是精髓,特意在此再次著重強調:
在決定哪個表做驅動表的時候,應該是兩個表按照各自的條件過濾,過濾完成之后,計算參與join的各個字段的總數據量,數據量小的那個表,就是“小表”,應該作為驅動表。
按照上面分析,我們先獨立思考下MySQL會選擇哪張表作為驅動表呢?
表t1,t2在字段a上都有索引不會全表掃描,其中t1.a=5條件過濾后只有一條,很顯然嘛,t1數據量少是小表,肯定是驅動表,錯不了,再說了前面的紅色粗體已經強調了,不會有錯的。
有冇搞錯?事實又被打臉了。還記得在開篇我們說過的mysql優化器會對sql語句進行優化的嗎?下面我們看下執行計劃與優化的sql語句:
格式化后的優化SQL如下:
優化后兩表t1,t2都走索引,并且都只有一條結果返回,因此都只會掃描一行,數據量一樣,所以誰在前面誰就是驅動表,也就是上面sql中表t2。一切都釋然,豁然開通!
回頭再仔細想想,高,實在是高!仔細深思之后MySQL優化后的句子真讓人猛拍大腿。高明之處在于:
1. 本來join連接是個M*N的嵌套循環,優化后變成了M+N的判斷,兩表不再嵌套判斷了。
2. 優化后,兩表沒有多大必然聯系,只需把兩表的結果集拼接即可,互不干擾。如果mysql未來可以多線程查詢,豈不十分快哉!
小伙伴們還記得我們在上一章 MySQL索引初探 中編碼類型不一致發生隱式轉換時有時候走索引,有時候索引又失效的問題嗎?下面我們選取有代表性的一條記錄來分析:
其中表demo_test總共有640條數據,demo_test_ass有3條數據。顯然經過過濾條件t.rid1完成后demo_test_ass數據量小,應該作為驅動表。雖然test.c_utf8mb4 = t.c2兩字段連接中發生了t.c2字段發生隱式轉換,但是實際上并不影響被驅動表test上的c_utf8mb4索引。
好了,本章到此結束,讓我們一起 總結一下MySQL驅動表與被驅動表的選取原則 :
?? ? 同等條件,優先選取有索引的表作為被驅動表。 在此介紹一下什么叫同等條件,比如上面的②中的語句。 兩表沒有其他額外的過濾條件,因此選關聯字段有索引的t1作為被驅動表。但是如果加了條件(and t1.id=3),此時t1數據量少,就選取了t2作為被驅動表。
??? MySQL選擇驅動表與被驅動表是基于優化器優化后的,小表是驅動表,大表是被驅動表。 基于優化器優化后開篇的 博文A與B 結論成立。
當然這都是我一家之言,并不是官方結論,目前暫未找到官方確切對于驅動表與被驅動表的解釋,請大家踴躍拍磚!