在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

介紹3種實(shí)現(xiàn)Nested-Loop Join算法的方法

冬至子 ? 來源:后端元宇宙 ? 作者:binron ? 2022-11-17 11:56 ? 次閱讀

在MySQL的實(shí)現(xiàn)中,Nested-Loop Join有3種實(shí)現(xiàn)的算法

  • Simple Nested-Loop Join:簡(jiǎn)單嵌套循環(huán)連接
  • Block Nested-Loop Join:緩存塊嵌套循環(huán)連接
  • Index Nested-Loop Join:索引嵌套循環(huán)連接

一、原理篇

1、Simple Nested-Loop Join

比如:

SELECT *
FROM user u
 LEFT JOIN class c ON u.id = c.user_id

我們來看一下當(dāng)進(jìn)行 join 操作時(shí),mysql是如何工作的:

圖片

當(dāng)我們進(jìn)行l(wèi)eft join連接操作時(shí),左邊的表是 「驅(qū)動(dòng)表」 ,右邊的表是**「被驅(qū)動(dòng)表」**

特點(diǎn)

Simple Nested-Loop Join 簡(jiǎn)單粗暴容易理解,就是通過雙層循環(huán)比較數(shù)據(jù)來獲得結(jié)果,但是這種算法顯然太過于粗魯,如果每個(gè)表有1萬條數(shù)據(jù),那么對(duì)數(shù)據(jù)比較的次數(shù)=1萬 * 1萬 =1億次,很顯然這種查詢效率會(huì)非常慢。

「這個(gè)全是磁盤掃描!」

?因?yàn)槊看螐尿?qū)動(dòng)表取數(shù)據(jù)比較耗時(shí),所以MySQL即使在沒有索引命中的情況下也并沒有采用這種算法來進(jìn)行連接操作,而是下面這種!

?

2、Block Nested-Loop Join

同樣以上面的sql為例,我們看下mysql是如何工作的

SELECT *
FROM user u
 LEFT JOIN class c ON u.id = c.user_id

圖片

因?yàn)槊看螐?code>驅(qū)動(dòng)表取一條數(shù)據(jù)都是磁盤掃描所有比較耗時(shí)。

這里就做了優(yōu)化就是 「每次從驅(qū)動(dòng)表取一批數(shù)據(jù)放到內(nèi)存中,然后對(duì)這一批數(shù)據(jù)進(jìn)行匹配操作」

這批數(shù)據(jù)匹配完畢,再?gòu)尿?qū)動(dòng)表中取一批數(shù)據(jù)放到內(nèi)存中,直到驅(qū)動(dòng)表的數(shù)據(jù)全都匹配完畢。

這塊內(nèi)存在MySQL中有一個(gè)專有的名詞,叫做 join buffer,我們可以執(zhí)行如下語句查看 join buffer 的大小

show variables like '%join_buffer%'

圖片

另外,Join Buffer緩存的對(duì)象是什么,這個(gè)問題相當(dāng)關(guān)鍵和重要。

?Join Buffer存儲(chǔ)的并不是驅(qū)動(dòng)表的整行記錄,具體指所有參與查詢的列都會(huì)保存到Join Buffer,而不是只有Join的列。

?

比如下面sql

SELECT a.col3
FROM a JOIN b ON a.col1 = b.col2
WHERE a.col2 > 0 AND b.col2 = 0

上述SQL語句的驅(qū)動(dòng)表是a,被驅(qū)動(dòng)表是b,那么存放在Join Buffer中的列是所有參與查詢的列,在這里就是(a.col1,a.col2,a.col3)。

也就是說查詢的字段越少,Join Buffer可以存的記錄也就越多!

變量join_buffer_size的默認(rèn)值是256K,顯然對(duì)于稍復(fù)雜的SQL是不夠用的。好在這個(gè)是會(huì)話級(jí)別的變量,可以在執(zhí)行前進(jìn)行擴(kuò)展。

建議在會(huì)話級(jí)別進(jìn)行設(shè)置,而不是全局設(shè)置,因?yàn)楹茈y給一個(gè)通用值去衡量。另外,這個(gè)內(nèi)存是會(huì)話級(jí)別分配的,如果設(shè)置不好容易導(dǎo)致因無法分配內(nèi)存而導(dǎo)致的宕機(jī)問題。

-- 調(diào)整到1M
set session join_buffer_size = 1024 * 1024 * 1024;
-- 再執(zhí)行查詢
SELECT a.col3
FROM a JOIN b ON a.col1 = b.col2
WHERE a.col2 > 0 AND b.col2 = 0

3、Index Nested-Loop Join

當(dāng)我們了解**「Block Nested-Loop Join」** 算法,我們發(fā)現(xiàn)雖然可以將驅(qū)動(dòng)表的數(shù)據(jù)放入 「Join Buffer」 中,但是緩存中的每條記錄都要和被驅(qū)動(dòng)表的所有記錄都匹配一遍,也會(huì)非常耗時(shí),所以我們應(yīng)該如何提高被驅(qū)動(dòng)表匹配的效率呢?

其實(shí)很簡(jiǎn)單 就是給被驅(qū)動(dòng)表連接的列加上索引,這樣匹配的過程就非常快,如圖所示

圖片

上面圖中就是先匹配索引看有沒有命中的數(shù)據(jù),有命中數(shù)據(jù)再回表查詢這條記錄,獲取其它所需要的數(shù)據(jù),但列的數(shù)據(jù)在索引中都能獲取那都不需要回表查詢,效率更高!

二、SQL示例

1、新增表和填充數(shù)據(jù)

-- 表1 a字段加索引 b字段沒加
CREATE TABLE `t1` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `a` int DEFAULT NULL COMMENT '字段a',
  `b` int DEFAULT NULL COMMENT '字段b',
  PRIMARY KEY (`id`),
  KEY `idx_a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 表2
 create table t2 like t1;
-- t1插入10000條數(shù)據(jù) t2插入100條數(shù)據(jù)
 drop procedure if exists insert_data;
 delimiter ;;
 create procedure insert_data()
 begin
 declare i int;
 set i = 1;
 while ( i <= 10000 ) do
 insert into t1(a,b) values(i,i);
  set i = i + 1;
 end while;
 set i = 1;
 while ( i <= 100) do
 insert into t2(a,b) values(i,i);
  set i = i + 1;
 end while;
 end;;
 delimiter ;
 call insert_data();

2、Block Nested-Loop Join算法示例

-- b字段沒有索引
explain select t2.* from t1 inner join t2 on t1.b= t2.b; 
-- 執(zhí)行結(jié)果
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows  | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
|  1 | SIMPLE      | t2    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   100 |   100.00 | NULL                                               |
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 10337 |    10.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+

從執(zhí)行計(jì)劃我們可以得出一些結(jié)論:

  • 驅(qū)動(dòng)表是t2,被驅(qū)動(dòng)表是t1。所以使用 inner join 時(shí),排在前面的表并不一定就是驅(qū)動(dòng)表。
  • Extra 中 的 「Using join buffer (Block Nested Loop)」 說明該關(guān)聯(lián)查詢使用的是 BNLJ 算法。

上面的sql大致流程是:

  1. 將 t2 的所有數(shù)據(jù)放入到 join_buffer
  2. 將 join_buffer 中的每一條數(shù)據(jù),跟表t1中所有數(shù)據(jù)進(jìn)行比較
  3. 返回滿足join 條件的數(shù)據(jù)

3、Index Nested-Loop Join 算法

-- a字段有索引
EXPLAIN select * from t1 inner join t2 on t1.a= t2.a;   
-- 執(zhí)行結(jié)果
+----+-------------+-------+------------+------+---------------+-------+---------+-----------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key   | key_len | ref             | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+-------+---------+-----------------+------+----------+-------------+
|  1 | SIMPLE      | t2    | NULL       | ALL  | idx_a         | NULL  | NULL    | NULL            |  100 |   100.00 | Using where |
|  1 | SIMPLE      | t1    | NULL       | ref  | idx_a         | idx_a | 5       | mall_order.t2.a |    1 |   100.00 | NULL        |
+----+-------------+-------+------------+------+---------------+-------+---------+-----------------+------+----------+-------------+

從執(zhí)行計(jì)劃我們可以得出一些結(jié)論:

  • 我們可以看出 t1的type不在是all而是ref,說明不在是全表掃描,而是走了idx_a的索引。
  • 這里并沒有出現(xiàn) 「Using join buffer (Block Nested Loop)」 ,說明走的是Index Nested-Loop Join。

上面的sql大致流程是:

  1. 從表 t2 中讀取一行數(shù)據(jù)
  2. 從第 1 步的數(shù)據(jù)中,取出關(guān)聯(lián)字段 a,到表 t1 idx_a 索引中查找;
  3. 從idx_a 索引上找到滿足條件的數(shù)據(jù),如果查詢數(shù)據(jù)在索引樹都能找到,那就可以直接返回,否則回表查詢剩余字段屬性再返回。
  4. 返回滿足join 條件的數(shù)據(jù)

我們發(fā)現(xiàn)這里效率最大的提升在于,t1表中rows=1,也就是說因?yàn)閕dx_a 索引的存在,不需要把t1每條數(shù)據(jù)都遍歷一遍,而是通過索引1次掃描可以認(rèn)為最終只掃描 t1 表一行完整數(shù)據(jù)。

三、join優(yōu)化總結(jié)

根據(jù)上面的知識(shí)點(diǎn)我們可以總結(jié)以下有關(guān)join優(yōu)化經(jīng)驗(yàn):

  1. 在關(guān)聯(lián)查詢的時(shí)候,盡量在被驅(qū)動(dòng)表的關(guān)聯(lián)字段上加索引,讓MySQL做join操作時(shí)盡量選擇INLJ算法

2)小表做驅(qū)動(dòng)表!

當(dāng)使用left join時(shí),左表是驅(qū)動(dòng)表,右表是被驅(qū)動(dòng)表,當(dāng)使用right join時(shí),右表是驅(qū)動(dòng)表,左表是被驅(qū)動(dòng)表,當(dāng)使用join時(shí),mysql會(huì)選擇數(shù)據(jù)量比較小的表作為驅(qū)動(dòng)表,大表作為被驅(qū)動(dòng)表,如果說我們?cè)?join的時(shí)候 明確知道哪張表是小表的時(shí)候,可以用 「straight_join」 寫法固定連接驅(qū)動(dòng)方式,省去mysql優(yōu)化器自己判斷的時(shí)間。

「對(duì)于小表定義的明確」

在決定哪個(gè)表做驅(qū)動(dòng)表的時(shí)候,應(yīng)該是兩個(gè)表按照各自的條件過濾,過濾完成之后,計(jì)算參與 join 的各個(gè)字段的總數(shù)據(jù)量,數(shù)據(jù)量小的那個(gè)表,就是“小表”,應(yīng)該作為驅(qū)動(dòng)表。

3)在適當(dāng)?shù)那闆r下增大 join buffer 的大小,當(dāng)然這個(gè)最好是在會(huì)話級(jí)別的增大,而不是全局級(jí)別

4)不要用 * 作為查詢列表,只返回需要的列!

這樣做的好處可以讓在相同大小的join buffer可以存更多的數(shù)據(jù),也可以在存在索引的情況下盡可能避免回表查詢數(shù)據(jù)。

審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • MySQL
    +關(guān)注

    關(guān)注

    1

    文章

    849

    瀏覽量

    27659
收藏 人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    FFT 算法的一 FPGA 實(shí)現(xiàn)

    FPGA實(shí)現(xiàn)的 FFT 處理器的硬件結(jié)構(gòu)。接收單元采用乒乓RAM 結(jié)構(gòu), 擴(kuò)大了數(shù)據(jù)吞吐量。中間數(shù)據(jù)緩存單元采用雙口RAM , 減少了訪問RAM 的時(shí)鐘消耗。計(jì)算單元采用基 2 算法, 流水線結(jié)構(gòu), 可在
    發(fā)表于 11-21 15:55

    DSP的實(shí)現(xiàn)方法

    芯片內(nèi)部用硬件實(shí)現(xiàn),無需進(jìn)行編程。在上述幾種方法中,第1種方法的缺點(diǎn)是速度較慢,一般可用于DSP算法的模擬;第2和第5
    發(fā)表于 08-27 13:47

    典型的ADRC算法介紹

    前言??上篇中詳細(xì)闡述了經(jīng)典的自抗擾控制算法的原理,本篇將圍繞兩ADRC算法展開,針對(duì)擴(kuò)張狀態(tài)觀測(cè)器的參數(shù)整定問題進(jìn)行詳解,同時(shí),對(duì)跟蹤微分器的幾個(gè)重要應(yīng)用進(jìn)行介紹。兩
    發(fā)表于 09-07 08:02

    Apriori算法的一優(yōu)化方法

    介紹關(guān)聯(lián)規(guī)則挖掘中的經(jīng)典算法――Apriori算法的關(guān)鍵思想。針對(duì)傳統(tǒng)Apriori算法效率上的不足,提出一改進(jìn)的Apriori
    發(fā)表于 04-10 08:48 ?19次下載

    3DES算法的FPGA高速實(shí)現(xiàn)

    摘要:介紹3-DES算法的概要;以Xilinx公司SPARTANII結(jié)構(gòu)的XC2S100為例,闡述用FPGA高速實(shí)現(xiàn)3-DES
    發(fā)表于 06-20 14:22 ?1536次閱讀
    <b class='flag-5'>3</b>DES<b class='flag-5'>算法</b>的FPGA高速<b class='flag-5'>實(shí)現(xiàn)</b>

    Viterbi譯碼器回溯算法實(shí)現(xiàn)

    該文介紹了兩Viterbi 譯碼器回溯譯碼算法,通過對(duì)這兩算法硬件實(shí)現(xiàn)結(jié)構(gòu)上的優(yōu)化,給出了這
    發(fā)表于 05-28 15:18 ?33次下載
    Viterbi譯碼器回溯<b class='flag-5'>算法</b><b class='flag-5'>實(shí)現(xiàn)</b>

    3像素歷遍方法的比較和實(shí)現(xiàn)_Delphi教程

    Delphi教程3像素歷遍方法的比較和實(shí)現(xiàn),很好的Delphi的學(xué)習(xí)資料。
    發(fā)表于 03-16 14:55 ?4次下載

    Join在Spark中是如何組織運(yùn)行的

    ,我們有必要了解Join在Spark中是如何組織運(yùn)行的。 SparkSQL總體流程介紹 在闡述Join實(shí)現(xiàn)之前,我們首先簡(jiǎn)單介紹SparkS
    的頭像 發(fā)表于 09-25 11:35 ?2436次閱讀
    <b class='flag-5'>Join</b>在Spark中是如何組織運(yùn)行的

    SQL子查詢優(yōu)化是怎么回事

    子查詢 (Subquery)的優(yōu)化一直以來都是 SQL 查詢優(yōu)化中的難點(diǎn)之一。 關(guān)聯(lián)子查詢的基本執(zhí)行方式類似于 Nested-Loop,但是這種執(zhí)行方式的效率常常低到難以忍受。 當(dāng)數(shù)據(jù)量稍大時(shí),必須
    的頭像 發(fā)表于 02-01 13:55 ?2291次閱讀
    SQL子查詢優(yōu)化是怎么回事

    介紹3種方法跨時(shí)鐘域處理方法

    介紹3跨時(shí)鐘域處理的方法,這3種方法可以說是FPGA界最常用也最實(shí)用的
    的頭像 發(fā)表于 09-18 11:33 ?2.3w次閱讀
    <b class='flag-5'>介紹</b><b class='flag-5'>3</b><b class='flag-5'>種方法</b>跨時(shí)鐘域處理<b class='flag-5'>方法</b>

    LOOP指令——匯編語言學(xué)習(xí)筆記3

    實(shí)現(xiàn)乘法的例子四、總結(jié)LOOP功能與格式功能:實(shí)現(xiàn)循環(huán)(計(jì)數(shù)型循環(huán))指令格式:LOOP 標(biāo)號(hào)一、LOOP指令實(shí)例以下是一個(gè)
    發(fā)表于 01-18 08:30 ?4次下載
    <b class='flag-5'>LOOP</b>指令——匯編語言學(xué)習(xí)筆記<b class='flag-5'>3</b>

    如何優(yōu)化MySQL中的join語句

    在mysql中,join 主要有Nested Loop、Hash Join、Merge Join 這三
    的頭像 發(fā)表于 04-24 17:03 ?1025次閱讀
    如何優(yōu)化MySQL中的<b class='flag-5'>join</b>語句

    一文終結(jié)SQL子查詢優(yōu)化

    子查詢(Subquery)的優(yōu)化一直以來都是 SQL 查詢優(yōu)化中的難點(diǎn)之一。關(guān)聯(lián)子查詢的基本執(zhí)行方式類似于 Nested-Loop,但是這種執(zhí)行方式的效率常常低到難以忍受。
    的頭像 發(fā)表于 04-28 14:19 ?977次閱讀
    一文終結(jié)SQL子查詢優(yōu)化

    大模型+多模態(tài)的3實(shí)現(xiàn)方法

    我們知道,預(yù)訓(xùn)練LLM已經(jīng)取得了諸多驚人的成就, 然而其明顯的劣勢(shì)是不支持其他模態(tài)(包括圖像、語音、視頻模態(tài))的輸入和輸出,那么如何在預(yù)訓(xùn)練LLM的基礎(chǔ)上引入跨模態(tài)的信息,讓其變得更強(qiáng)大、更通用呢?本節(jié)將介紹“大模型+多模態(tài)”的3
    的頭像 發(fā)表于 12-13 13:55 ?2459次閱讀
    大模型+多模態(tài)的<b class='flag-5'>3</b><b class='flag-5'>種</b><b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>方法</b>

    arduino如何停止loop循環(huán)

    退出這個(gè)循環(huán)。本文將詳細(xì)介紹如何在Arduino中停止loop循環(huán)。 在Arduino中,可以通過使用一個(gè)布爾變量或條件語句來實(shí)現(xiàn)停止loop循環(huán)的功能。下面我們將逐步討論這些
    的頭像 發(fā)表于 02-14 16:24 ?5670次閱讀
    主站蜘蛛池模板: 天堂中文字幕 | 日本午夜片成年www 日本午夜三级 | 国产精品伦子一区二区三区 | 久久综合久久88 | 97综合| 五月天婷婷网站 | 精品久久久久久中文字幕欧美 | 日本欧美午夜 | 久久国产精品免费网站 | 在线播放色 | 色v在线 | 国产caob | 欧美日韩亚洲色图 | 亚洲国产高清精品线久久 | 国产免费卡1卡2卡 | 2018天天干夜夜操 | 国产成人一区二区在线不卡 | 欧美一级日韩一级亚洲一级 | 亚洲欧美强伦一区二区另类 | 亚洲美女激情视频 | 欧美大狠狠大臿蕉香蕉大视频 | 国产精品毛片一区二区三区 | 加勒比一木道|视频在线看 加勒比在线免费视频 | 色天天天天 | 人人做人人干 | 扛着高跟鞋丝袜腿呻吟视频 | 日本a级片在线观看 | 久久久久国产一级毛片高清版 | 黄视频在线播放 | 26uuu另类欧美亚洲曰本 | 手机在线色| 三级网站在线免费观看 | 性久久久久久久久 | 美女用手扒开尿口给男生桶爽 | 久青草国产观看在线视频 | 激情免费视频 | 天天在线精品视频在线观看 | 丁香六月色婷婷 | 中文字幕色网站 | 天天摸天天做天天爽在线 | 夜夜夜爽 |