目錄
#索引對join 查詢的影響
資料準備
有索引查詢流程
#重複執行步驟1-3,直到表t1 循環資料
如何正确的写出 join 查询
驱动表的选择
什么是小表
首頁 資料庫 mysql教程 簡單聊聊MySQL中join查詢

簡單聊聊MySQL中join查詢

Nov 03, 2022 pm 04:49 PM
mysql

這篇文章為大家帶來了關於mysql的相關知識,其中主要介紹了關於join查詢的相關問題,下面一起來看一下,希望對大家有幫助。

推薦學習:mysql影片教學

#索引對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 <h3 id="strong-有索引查詢流程-strong"><strong>有索引查詢流程</strong></h3><p>我們使用查詢SELECT * FROM t1 STRAIGHT_JOIN t2 ON (t1.a=t2.a);因為join 查詢MYSQL 優化器不一定能按照我們的意願去執行,所以為了分析我們選擇用STRAIGHT_JOIN 來代替,從而更直觀的進行觀察</p><p> 圖1</p><p>#可以看出我們使用了t1 作為驅動表,t2 作為被驅動表,上圖的explain 中顯示本次查詢用上了t2 表的字段a索引,所以這個語句的執行過程應該是下面這樣的:</p>
登入後複製
  • 從t1 表中讀取一行資料r

  • 從資料r中取出欄位a到表t2 中進行比對

取出t2 表中符合條件的行,和r組成一行作為結果集的一部分

#重複執行步驟1-3,直到表t1 循環資料

該過程稱之為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. 了解

Block Nested-Loop Join

#Block Nested-Loop Join

查詢流程

那麼被驅動表上沒有存在索引,這一切都是怎麼發生的呢?

其實當被驅動表上沒有可用的索引,演算法流程是這樣的:

###把t1 的資料讀取執行緒記憶體join_buffer 中,因為上述我們寫的是select * from,所以相當於把整個t1 表放入了內存;############掃描t2 的過程,實際上是把t2 的每一行取出來,跟join_buffer 中的資料去做對比,滿足join 條件的,作為結果集的一部分進行回傳。 #####################所以結合圖2中Extra 部分說明Using join buffer 可以發現這一絲端倪,整個過程中,對錶t1 和t2 都做了一次全表掃描,因此掃描的行數是100 1000=1100 行,因為join_buffer 是以無序數組的方式組織的,因此對於表t2 中每一行,都要做​​100 次判斷,總共需要在內存中進行的判斷次數是100*1000=10 萬次,但因為這10 萬次是發生在記憶體的所以速度要快很多,效能也更好。 #########Join_buffer#########根據上述已經知道了,沒有索引的情況下MySQL 是將資料讀取記憶體進行循環判斷的,那麼這個記憶體肯定不是無限制讓你使用的,這時我們需要用到一個參數join_buffer_size,該值預設大小256k,如下圖:###
SHOW VARIABLES LIKE '%join_buffer_size%';
登入後複製
###########圖4#######假如查詢的資料過大一次載入不完,只能夠載入部分資料(80 個),那麼查詢的過程就變成了下面這樣###
  • 扫描表 t1,顺序读取数据行放入 join_buffer 中,直至加载完第 80 行满了

  • 扫描表 t2,把 t2 表中的每一行取出来跟 join_buffer 中的数据做对比,将满足条件的数据作为结果集的一部分返回

  • 清空 join_buffer

  • 继续扫描表 t1,顺序读取剩余的数据行放入 join_buffer 中,执行步骤 2

这个流程体现了算法名称中 Block 的由来,分块 join,可以看出虽然查询过程中 t1 被分成了两次放入 join_buffer 中,导致 t2 表被扫描了 2次,但是判断等值条件的次数还是不变的,依然是(80+20)*1000=10 万次。

所以这就是有时候 join 查询很慢,有些大佬会让你把 join_buffer_size 调大的原因。

如何正确的写出 join 查询

驱动表的选择

  • 有索引的情况下

在这个 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 <p>上面这两条 SQL 我们加上了条件 t2.id </p><p>再看另一组:</p><pre class="brush:php;toolbar:false">SELECT t1.b,t2.* FROM t1 STRAIGHT_JOIN t2 ON t1.b = t2.b WHERE t2.id <p>这个例子里,表 t1 和 t2 都是只有 100 行参加 join。 但是,这两条语句每次查询放入 join_buffer 中的数据是不一样的: 表 t1 只查字段 b,因此如果把 t1 放到 join_buffer 中,只需要放入字段 b 的值; 表 t2 需要查所有的字段,因此如果把表 t2 放到 join_buffer 中的话,就需要放入三个字 段 id、a 和 b。</p><p>这里,我们应该选择表 t1 作为驱动表。也就是说在这个例子里,”只需要一列参与 join 的 表 t1“是那个相对小的表。</p><p>结论:</p><p>在决定哪个表做驱动表的时候,应该是两个表按照各自的条件过滤,过 滤完成之后,计算参与 join 的各个字段的总数据量,数据量小的那个表,就是“小表”, 应该作为驱动表。</p><p>推荐学习:<a href="https://www.php.cn/course/list/51.html" target="_blank" textvalue="mysql视频教程">mysql视频教程</a></p>
登入後複製

以上是簡單聊聊MySQL中join查詢的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

mysql:簡單的概念,用於輕鬆學習 mysql:簡單的概念,用於輕鬆學習 Apr 10, 2025 am 09:29 AM

MySQL是一個開源的關係型數據庫管理系統。 1)創建數據庫和表:使用CREATEDATABASE和CREATETABLE命令。 2)基本操作:INSERT、UPDATE、DELETE和SELECT。 3)高級操作:JOIN、子查詢和事務處理。 4)調試技巧:檢查語法、數據類型和權限。 5)優化建議:使用索引、避免SELECT*和使用事務。

phpmyadmin怎麼打開 phpmyadmin怎麼打開 Apr 10, 2025 pm 10:51 PM

可以通過以下步驟打開 phpMyAdmin:1. 登錄網站控制面板;2. 找到並點擊 phpMyAdmin 圖標;3. 輸入 MySQL 憑據;4. 點擊 "登錄"。

navicat premium怎麼創建 navicat premium怎麼創建 Apr 09, 2025 am 07:09 AM

使用 Navicat Premium 創建數據庫:連接到數據庫服務器並輸入連接參數。右鍵單擊服務器並選擇“創建數據庫”。輸入新數據庫的名稱和指定字符集和排序規則。連接到新數據庫並在“對象瀏覽器”中創建表。右鍵單擊表並選擇“插入數據”來插入數據。

MySQL:世界上最受歡迎的數據庫的簡介 MySQL:世界上最受歡迎的數據庫的簡介 Apr 12, 2025 am 12:18 AM

MySQL是一種開源的關係型數據庫管理系統,主要用於快速、可靠地存儲和檢索數據。其工作原理包括客戶端請求、查詢解析、執行查詢和返回結果。使用示例包括創建表、插入和查詢數據,以及高級功能如JOIN操作。常見錯誤涉及SQL語法、數據類型和權限問題,優化建議包括使用索引、優化查詢和分錶分區。

為什麼要使用mysql?利益和優勢 為什麼要使用mysql?利益和優勢 Apr 12, 2025 am 12:17 AM

選擇MySQL的原因是其性能、可靠性、易用性和社區支持。 1.MySQL提供高效的數據存儲和檢索功能,支持多種數據類型和高級查詢操作。 2.採用客戶端-服務器架構和多種存儲引擎,支持事務和查詢優化。 3.易於使用,支持多種操作系統和編程語言。 4.擁有強大的社區支持,提供豐富的資源和解決方案。

navicat怎麼新建連接mysql navicat怎麼新建連接mysql Apr 09, 2025 am 07:21 AM

可在 Navicat 中通過以下步驟新建 MySQL 連接:打開應用程序並選擇“新建連接”(Ctrl N)。選擇“MySQL”作為連接類型。輸入主機名/IP 地址、端口、用戶名和密碼。 (可選)配置高級選項。保存連接並輸入連接名稱。

redis怎麼使用單線程 redis怎麼使用單線程 Apr 10, 2025 pm 07:12 PM

Redis 使用單線程架構,以提供高性能、簡單性和一致性。它利用 I/O 多路復用、事件循環、非阻塞 I/O 和共享內存來提高並發性,但同時存在並發性受限、單點故障和不適合寫密集型工作負載的局限性。

MySQL和SQL:開發人員的基本技能 MySQL和SQL:開發人員的基本技能 Apr 10, 2025 am 09:30 AM

MySQL和SQL是開發者必備技能。 1.MySQL是開源的關係型數據庫管理系統,SQL是用於管理和操作數據庫的標準語言。 2.MySQL通過高效的數據存儲和檢索功能支持多種存儲引擎,SQL通過簡單語句完成複雜數據操作。 3.使用示例包括基本查詢和高級查詢,如按條件過濾和排序。 4.常見錯誤包括語法錯誤和性能問題,可通過檢查SQL語句和使用EXPLAIN命令優化。 5.性能優化技巧包括使用索引、避免全表掃描、優化JOIN操作和提升代碼可讀性。

See all articles