成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

深入理解MySQL中的Join算法

數據庫 MySQL
MySQL在執行Join操作時使用了多種高效的算法,包括Index Nested-Loop Join(NLJ)和Block Nested-Loop Join(BNL)。這些算法各有優缺點,本文將探討這兩種算法的工作原理,以及如何在MySQL中使用它們。

在數據庫處理中,Join操作是最基本且最重要的操作之一,它能將不同的表連接起來,實現對數據集的更深層次分析。

MySQL作為一款流行的關系型數據庫管理系統,其在執行Join操作時使用了多種高效的算法,包括Index Nested-Loop Join(NLJ)和Block Nested-Loop Join(BNL)。這些算法各有優缺點,本文將探討這兩種算法的工作原理,以及如何在MySQL中使用它們。

什么是Join

在MySQL中,Join是一種用于組合兩個或多個表中數據的查詢操作。Join操作通?;趦蓚€表中的某些共同的列進行,這些列在兩個表中都存在。MySQL支持多種類型的Join操作,如Inner Join、Left Join、Right Join等。

Inner Join是最常見的Join類型之一。在Inner Join操作中,只有在兩個表中都存在的行才會被返回。

例如,如果我們有一個“customers”表和一個“orders”表,我們可以通過在這兩個表中共享“customer_id”列來組合它們的數據。


SELECT *
FROM customers
INNER JOIN orders
ON customers.customer_id = orders.customer_id;

上面的查詢將返回所有存在于“customers”和“orders”表中的“customer_id”列相同的行。

Index Nested-Loop Join

Index Nested-Loop Join(NLJ)算法是Join算法中最基本的算法之一。

在NLJ算法中,MySQL首先會選擇一個表(通常是小型表)作為驅動表,并迭代該表中的每一行。然后,MySQL在第二個表中搜索匹配條件的行,這個搜索過程通常使用索引來完成。一旦找到匹配的行,MySQL將這些行組合在一起,并將它們作為結果集返回。

工作流程如圖:

例如,執行下面這個語句:

select * from t1 straight_join t2 on (t1.a=t2.a);

注:當使用 straight_join 時,MySQL會強制按照在查詢中指定的從左到右的順序執行連接。

在這個語句里,假設 t1 是驅動表,t2 是被驅動表。我們來看一下這條語句的explain結果。

可以看到,在這條語句里,被驅動表t2的字段a上有索引,join過程用上了這個索引,因此這個語句的執行流程是這樣的:

  • 從表t1中讀入一行數據 R;
  • 從數據行R中,取出a字段到表t2里去查找;
  • 取出表t2中滿足條件的行,跟R組成一行,作為結果集的一部分;
  • 重復執行步驟1到3,直到表t1的末尾循環結束。

這個過程就跟我們寫程序時的嵌套查詢類似,并且可以用上被驅動表的索引,所以我們稱之為「Index Nested-Loop Join」,簡稱NLJ。

NLJ是使用上了索引的情況,那如果查詢條件沒有使用到索引呢?

MySQL會選擇使用另一個叫作「Block Nested-Loop Join」的算法,簡稱BNL。

Block Nested-Loop Join

Block Nested Loop Join(BNL)算法與NLJ算法不同的是,BNL算法使用一個類似于緩存的機制,將表數據分成多個塊,然后逐個處理這些塊,以減少內存和CPU的消耗。

例如,執行下面這個語句:

select * from t1 straight_join t2 on (t1.a=t2.b);

如果 t2 表的字段b上是沒有建立索引的。這時候,被驅動表上沒有可用的索引,算法的流程是這樣的:

  • 把表t1的數據讀入線程內存join_buffer中,由于我們這個語句中寫的是select *,因此是把整個表t1放入了內存;
  • 掃描表t2,把表t2中的每一行取出來,跟join_buffer中的數據做對比,滿足join條件的,作為結果集的一部分返回。

這條SQL語句的explain結果如下所示:

可以看到,在這個過程中,MySQL對表 t1 和 t2 都做了一次全表掃描,因此總的掃描行數是1100。

由于join_buffer是以無序數組的方式組織的,因此對表t2中的每一行,都要做100次判斷,總共需要在內存中做的判斷次數是:100*1000=10萬次。

雖然Block Nested-Loop Join算法是全表掃描。但是是在內存中進行的判斷操作,速度上會快很多。但是性能仍然不如NLJ。

join_buffer的大小是由參數join_buffer_size設定的,默認值是256k。

那如果join_buffer_size的大小不足以放下表t1的所有數據呢?

辦法很簡單,就是分段放,執行流程如下:

  • 順序讀取數據行放入join_buffer中,直到join_buffer滿了。
  • 掃描被驅動表跟join_buffer中的數據做對比,滿足join條件的,作為結果集的一部分返回。
  • 清空join_buffer,重復上述步驟。

雖然分成多次放入join_buffer,但是判斷等值條件的次數還是不變的,依然是10萬次。

MRR & BKA

上篇文章里我們有提到MRR(Multi-Range Read)。MySQL在5.6版本后引入了**Batched Key Acess(BKA)**算法,這個BKA算法,其實就是對NLJ算法的優化,而BKA算法正是基于MRR。

NLJ算法執行的邏輯是:從驅動表t1,一行行地取出a的值,再到被驅動表t2去做join。也就是說,對于表t2來說,每次都是匹配一個值。這時,MRR的優勢就用不上了。

其實我們可以從表t1里一次性地多拿些行出來,先放到一個臨時內存,一起傳給表t2。這個臨時內存不是別人,就是join_buffer。

通過上一篇文章,我們知道join_buffer 在BNL算法里的作用,是暫存驅動表的數據。但是在NLJ算法里并沒有用。那么,我們剛好就可以復用join_buffer到BKA算法中。

NLJ算法優化后的BKA算法的流程,如圖所示:

圖中,在join_buffer中放入的數據是R1~R100,表示的是只會取查詢需要的字段。當然,如果join buffer放不下R1~R100的所有數據,就會把這100行數據分成多段執行上圖的流程。

如果要使用BKA優化算法的話,你需要在執行SQL語句之前,先設置:

set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

其中,前兩個參數的作用是要啟用MRR。這么做的原因是,BKA算法的優化要依賴于MRR。

對于BNL,我們可以通過建立索引轉為BKA。但是,有時候你確實會碰到一些不適合在被驅動表上建索引的情況。比如下面這個語句:

select * from t1 join t2 on (t1.b=t2.b) where t2.b>=1 and t2.b<=2000;

假設t1表1000行,t2表100萬行,t2.b<=2000過濾后,t2表需要參與join的只有2000行數據。

如果這條語句是一個低頻的SQL語句,那么在表t2的字段b上創建索引就很浪費了。

這時候,我們可以考慮使用臨時表。使用臨時表的大致思路是:

  • 把表t2中滿足條件的數據放在臨時表tmp_t中;
  • 為了讓join使用BKA算法,給臨時表tmp_t的字段b加上索引;
  • 讓表t1和tmp_t做join操作。

此時,對應的SQL語句的寫法如下:

create temporary table temp_t(id int primary key, a int, b int, index(b))engine=innodb;
insert into temp_t select * from t2 where b>=1 and b<=2000;
select * from t1 join temp_t on (t1.b=temp_t.b);

總體來看,不論是在原表上加索引,還是用有索引的臨時表,我們的思路都是讓join語句能夠用上被驅動表上的索引,來觸發BKA算法,提升查詢性能。

總結

在MySQL中,不管Join使用的是NLJ還是BNL總是應該使用小表做驅動表。更準確地說,在決定哪個表做驅動表的時候,應該是兩個表按照各自的條件過濾,過濾完成之后,計算參與join的各個字段的總數據量,數據量小的那個表,就是“小表”,應該作為驅動表。

另外應當盡量避免使用BNL算法,如果確認優化器會使用BNL算法,就需要做優化。優化的常見做法是,給被驅動表的join字段加上索引,把BNL算法轉成BKA算法。對于不好在索引的情況,可以基于臨時表的改進方案,提前過濾出小數據添加索引。

責任編輯:趙寧寧 來源: Java隨想錄
相關推薦

2025-05-06 00:43:00

MySQL日志文件MIXED 3

2024-07-18 10:12:04

2023-10-31 10:51:56

MySQLMVCC并發性

2020-07-10 08:15:19

遞歸算法函數

2017-07-26 15:59:51

尋路算法Dijkstra游戲

2010-06-28 10:12:01

PHP匿名函數

2014-06-23 10:42:56

iOS開發UIScrollVie

2016-08-31 15:50:50

PythonThreadLocal變量

2018-07-09 15:11:14

Java逃逸JVM

2020-12-16 09:47:01

JavaScript箭頭函數開發

2010-06-01 15:25:27

JavaCLASSPATH

2016-12-08 15:36:59

HashMap數據結構hash函數

2020-07-21 08:26:08

SpringSecurity過濾器

2020-03-17 08:36:22

數據庫存儲Mysql

2023-10-13 13:30:00

MySQL鎖機制

2020-03-26 16:40:07

MySQL索引數據庫

2013-11-05 13:29:04

JavaScriptreplace

2013-06-20 10:25:56

2024-08-29 08:41:50

2012-11-22 10:11:16

LispLisp教程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久亚洲国产 | 欧洲成人免费视频 | 日韩欧美中文在线 | 日批日韩在线观看 | 91视频播放 | 久久久久久久综合色一本 | 在线观看中文字幕亚洲 | 天天爽一爽 | 91在线看网站 | 中文字幕91 | 久久久久久国产精品 | 久久一区二区视频 | 午夜精品久久久久久久星辰影院 | 日日天天 | 91在线导航| 久久视频免费看 | 黑人巨大精品欧美一区二区免费 | 不卡视频一区二区三区 | www.亚洲| 日韩欧美在线视频 | 99免费 | 成人国产精品色哟哟 | 国产精品一区二区在线 | 成人在线视频免费观看 | 国产精品久久av | 精品欧美色视频网站在线观看 | 久久福利电影 | 综合网中文字幕 | 最新中文字幕久久 | 一区二区三区精品视频 | 毛片网在线观看 | 91精品国产综合久久香蕉922 | 国产精品久久久久久福利一牛影视 | 久久久性色精品国产免费观看 | 4hu最新网址 | 自拍偷拍3p | 国产成人精品久久二区二区 | 久久免费小视频 | 91av在线免费播放 | 精品国产一区二区三区久久 | 久久精品久久精品久久精品 |