<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
相信大家 MySQL 都用了很久了,各種 join 查詢天天都在寫,但是 join 查詢到底是怎麼查的,怎麼寫才是最正確的,今天我就和大家一起學習探討一下
假設有兩張表 t1、t2,兩張表都存在有主鍵索引 id 和索引欄位 a,b 欄位無索引,然後在 t1 表中插入 100 行資料,t2 表中插入 1000 行資料進行實驗
CREATE TABLE `t2` ( `id` int NOT NULL, `a` int DEFAULT NULL, `b` int DEFAULT NULL, PRIMARY KEY (`id`), KEY `t2_a_index` (`a`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; CREATE PROCEDURE **idata**() BEGIN DECLARE i INT; SET i = 1; WHILE (i <= 1000)do INSERT INTO t2 VALUES (i,i,i); SET i = i +1; END WHILE; END; CALL **idata**(); CREATE TABLE t1 LIKE t2; INSERT INTO t1 (SELECT * FROM t2 WHERE id <= 100);
我們使用查詢 SELECT * FROM t1 STRAIGHT_JOIN t2 ON (t1.a=t2.a);因為 join 查詢 MYSQL 優化器不一定能按照我們的意願去執行,所以為了分析我們選擇用 STRAIGHT_JOIN 來代替,從而更直觀的進行觀察
圖 1
可以看出我們使用了 t1 作為驅動表,t2 作為被驅動表,上圖的 explain 中顯示本次查詢用上了 t2 表的欄位 a索引,所以這個語句的執行過程應該是下面這樣的:
該過程稱之為 Index Nested-Loop Join,在這個流程裡,驅動表 t1 進行了全表掃描,因為我們給 t1 表插入了 100 行資料,所以本次的掃描行數是 100,而進行 join 查詢時,對於 t1 表的每一行都需去 t2 表中進行查詢,走的是索引樹搜尋,因為我們構造的資料都是一一對應的,所以每次搜尋只掃描一行,也就是 t2 表也是總共掃描 100 行,整個查詢過程掃描的總行數是 100+100=200 行。
SELECT * FROM t1 STRAIGHT_JOIN t2 ON (t1.a = t2.b);
圖 2
可以看出由於 t2 表欄位 B上沒有索引,所以按照上述 SQL 執行時每次從 t1 去匹配 t2 的時候都要做一次全表掃描,這樣算下來掃描 t2 多大 100 次,總掃描次數就是 100*1000 = 10 萬行。
當然了這個查詢結果還是在我們建的這兩個都是小表的情況下,如果是數量級 10 萬行的表,就需要掃描 100 億行,這就太恐怖了!
那麼被驅動表上沒有存在索引,這一切都是怎麼發生的呢?
實際上當被驅動表上沒有可用的索引,演演算法流程是這樣的:
所以結合圖 2中 Extra 部分說明 Using join buffer 可以發現這一絲端倪,整個過程中,對錶 t1 和t2 都做了一次全表掃描,因此掃描的行數是 100+1000=1100 行,因為 join_buffer 是以無序陣列的方式組織的,因此對於表 t2 中每一行,都要做 100 次判斷,總共需要在記憶體中進行的判斷次數是 100*1000=10 萬次,但是因為這 10 萬次是發生在記憶體中的所以速度上要快很多,效能也更好。
根據上述已經知道了,沒有索引的情況下 MySQL 是將資料讀取記憶體進行迴圈判斷的,那麼這個記憶體肯定不是無限制讓你使用的,這時我們就需要用到一個引數 join_buffer_size,該值預設大小 256k,如下圖:
SHOW VARIABLES LIKE '%join_buffer_size%';
圖 4
假如查詢的資料過大一次載入不完,只能夠載入部分資料(80 條),那麼查詢的過程就變成了下面這樣
這個流程體現了演演算法名稱中 Block 的由來,分塊 join,可以看出雖然查詢過程中 t1 被分成了兩次放入 join_buffer 中,導致 t2 表被掃描了 2次,但是判斷等值條件的次數還是不變的,依然是(80+20)*1000=10 萬次。
所以這就是有時候 join 查詢很慢,有些大佬會讓你把 join_buffer_size 調大的原因。
在這個 join 語句執行過程中,驅動表是走全表掃描,而被驅動表是走樹搜尋。
假設被驅動表的行數是 M,每次在被驅動表查詢一行資料,先要走索引 a,再搜尋主鍵索引。每次搜尋一棵樹近似複雜度是以 2為底的 M的對數,記為 log2M,所以在被驅動表上查詢一行資料的時間複雜度是 2*log2M。
假設驅動表的行數是 N,執行過程就要掃描驅動表 N 行,然後對於每一行,到被驅動表上 匹配一次。因此整個執行過程,近似複雜度是 N + N2log2M。顯然,N 對掃描行數的影響更大,因此應該讓小表來做驅動表。
上述我知道了,因為 join_buffer 因為存在限制,所以查詢的過程可能存在多次載入 join_buffer,但是判斷的次數都是 10 萬次,這種情況下應該怎麼選擇?
假設,驅動表的資料行數是 N,需要分 K 段才能完成演演算法流程,被驅動表的資料行數是 M。這裡的 K不是常數,N 越大 K就越大,因此把 K 表示為λ*N,顯然λ的取值範圍 是 (0,1)。
掃描的行數就變成了 N+λNM,顯然記憶體的判斷次數是不受哪個表作為驅動表而影響的,而考慮到掃描行數,在 M和 N大小確定的情況下,N 小一些,整個算是的結果會更小,所以應該讓小表作為驅動表
總結:真相大白了,不管是有索引還是無索引參與 join 查詢的情況下都應該是使用小表作為驅動表。
還是以上面表 t1 和表 t2 為例子:
SELECT * FROM t1 STRAIGHT_JOIN t2 ON t1.b = t2.b WHERE t2.id <= 50; SELECT * FROM t2 STRAIGHT_JOIN t1 ON t1.b = t2.b WHERE t2.id <= 50;
上面這兩條 SQL 我們加上了條件 t2.id <= 50,我們使用了欄位 b,所以兩條 SQL 都沒有用上索引,但是第二條 SQL 可以看出 join_buffer 只需要放入前 50 行,顯然查詢更快,所以 t2 的前 50 行就是那個相對較小的表,也就是我們上面說所說的‘小表’。
再看另一組:
SELECT t1.b,t2.* FROM t1 STRAIGHT_JOIN t2 ON t1.b = t2.b WHERE t2.id <= 100; SELECT t1.b,t2.* FROM t2 STRAIGHT_JOIN t1 ON t1.b = t2.b WHERE t2.id <= 100;
這個例子裡,表 t1 和 t2 都是隻有 100 行參加 join。 但是,這兩條語句每次查詢放入 join_buffer 中的資料是不一樣的: 表 t1 只查欄位 b,因此如果把 t1 放到 join_buffer 中,只需要放入欄位 b 的值; 表 t2 需要查所有的欄位,因此如果把表 t2 放到 join_buffer 中的話,就需要放入三個字 段 id、a 和 b。
這裡,我們應該選擇表 t1 作為驅動表。也就是說在這個例子裡,”只需要一列參與 join 的 表 t1“是那個相對小的表。
在決定哪個表做驅動表的時候,應該是兩個表按照各自的條件過濾,過 濾完成之後,計算參與 join 的各個欄位的總資料量,資料量小的那個表,就是“小表”, 應該作為驅動表。
到此這篇關於MySQL中join查詢的文章就介紹到這了,更多相關MySQL join查詢內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45