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

InnoDB B-TREE 索引怎么計算 WHERE 條件范圍內(nèi)有多少條記錄?

數(shù)據(jù)庫 MySQL
一個 WHERE 條件范圍(例如 WHERE a >= 100 AND a <= 200),就是一個掃描區(qū)間 [100, 200],掃描區(qū)間有起點和終點,本文中我們把掃描區(qū)間的起點叫作 左端點,終點叫作右端點。

MySQL 為一個表選擇讀取數(shù)據(jù)的方式,取決于這種方式的執(zhí)行成本。

如果 WHERE 條件能夠命中索引(包含主鍵索引、二級索引),計算 WHERE 條件范圍內(nèi)的記錄數(shù)量,是計算使用索引執(zhí)行查詢的成本的關(guān)鍵指標(biāo)。

本文我們就一起來看看這個關(guān)鍵指標(biāo)是怎么計算的?

本文內(nèi)容基于 MySQL 8.0.29 源碼。

正文

1、整體概覽

一個 WHERE 條件范圍(例如 WHERE a >= 100 AND a <= 200),就是一個掃描區(qū)間 [100,200],掃描區(qū)間有起點和終點,本文中我們把掃描區(qū)間的起點叫作 左端點,終點叫作右端點。

計算 WHERE 條件范圍內(nèi)有多少條記錄,就是計算其對應(yīng)的掃描區(qū)間有多少條記錄,整體來看,會經(jīng)過兩大步驟:

第 1 步,定位索引葉結(jié)點中掃描區(qū)間左端點、右端點對應(yīng)的記錄。

這個過程是從根結(jié)點開始自上而下進行的。

經(jīng)過索引的每一層,會分別把該層中左端點、右端點記錄所在索引頁的頁號,保存到數(shù)組里,得到從根結(jié)點到葉結(jié)點中的左端點、右端點記錄經(jīng)過的索引頁的路徑。

左端點路徑保存在數(shù)組 path1 中,右端點路徑保存在數(shù)組 path2 中,如下圖所示:

圖片

以一個 3 層的 B-TREE 索引為例,來說明這個自上而下的定位過程:

定位索引葉結(jié)點中掃描區(qū)間左端點、右端點記錄,是獨立進行的,但是執(zhí)行流程完全一樣,所以放在一起介紹了。

首先,在根結(jié)點中,左端點、右端點記錄都在根結(jié)點范圍內(nèi),path1[0]、path2[0] 中都會保存根結(jié)點的頁號。

左右端點對應(yīng)的記錄,可能是根結(jié)點中的同一條記錄或不同記錄。

讀取根結(jié)點中左端點、右端點記錄指向的子結(jié)點的頁號。

然后,進入左端點、右端點記錄對應(yīng)的內(nèi)結(jié)點,path1[1] 中保存左端點記錄所在內(nèi)結(jié)點的頁號,path2[1] 中保存右端點記錄所在內(nèi)結(jié)點的頁號。

左右端點對應(yīng)的記錄,可能是不同內(nèi)結(jié)點中的記錄,也可能是相同內(nèi)結(jié)點中的同一條記錄或不同記錄。

讀取左端點、右端點在各自內(nèi)結(jié)點中對應(yīng)的記錄指向的葉結(jié)點的頁號。

最后,進入左端點、右端點記錄對應(yīng)的葉結(jié)點,path1[2] 中保存左端點記錄所在葉結(jié)點的頁號,path2[2] 中保存右端點記錄所在葉結(jié)點的頁號。

左右端點對應(yīng)的記錄,可能是不同葉結(jié)點中的記錄,也可能是相同葉結(jié)點中的同一條記錄或不同記錄。

關(guān)于定位掃描區(qū)間左端點、右端點記錄的過程,上一篇文章中有詳細介紹,感興趣的小伙伴可以點擊這個鏈接閱讀:InnoDB B-TREE

索引怎么定位一條記錄?

第 2 步,計算掃描區(qū)間的記錄數(shù)量。

經(jīng)過第 1 步,得到了左右端兩個路徑數(shù)組,數(shù)組中保存著從根結(jié)點到葉結(jié)點,掃描區(qū)間左右端點所經(jīng)過的每一個索引頁的頁號。

計算掃描區(qū)間包含多少條記錄,最終是要計算葉結(jié)點所在的層級,掃描區(qū)間中包含的記錄數(shù)量。

由于葉結(jié)點所在的層級,掃描區(qū)間中的記錄可能會分散在很多很多個連續(xù)的葉結(jié)點中,挨個讀取掃描區(qū)間中的所有葉結(jié)點的記錄數(shù)量是不現(xiàn)實的,這就需要借助葉結(jié)點的上層結(jié)點了。

上層結(jié)點中的記錄數(shù)量就是其管轄范圍內(nèi)的葉結(jié)點的數(shù)量。

然而,葉結(jié)點的上層結(jié)點所在的層級,也可能有很多很多的同級結(jié)點,那又需要借助更上一層結(jié)點,這樣逐層往上推,最終可能需要讀取根結(jié)點有多少個子結(jié)點。

正是因為計算掃描區(qū)間包含多少條記錄,可能需要依賴上層結(jié)點,在源碼的實現(xiàn)中,這個過程也是從根結(jié)點自上而下進行的。

自上而下進行的過程,就是遍歷左端點、右端點路徑數(shù)組,計算每一層從左端點記錄到右端點記錄這個區(qū)間內(nèi)包含的記錄數(shù)量,最終到達葉結(jié)點所在的層級,得到掃描區(qū)間的記錄數(shù)量。

源碼的實現(xiàn)自上而下進行,文章卻不能這么寫,否則陷入代碼細節(jié),寫出來也很晦澀難懂。

接下來,我們根據(jù)掃描區(qū)間左端點、右端點記錄在葉結(jié)點中的不同位置,分場景介紹計算掃描區(qū)間的記錄數(shù)量的過程,請大家保持愉悅的心情看下去,可能會更容易看懂

^_^

2、 場景分析

我們分場景進行介紹是為了更好理解,但是,不同場景下都會涉及到一些又臭又長并且需要重復(fù)描述的定義。

在更好理解的基礎(chǔ)上,我們也要盡量保持內(nèi)容的簡潔,為此,把一些需要重復(fù)描述的定義在這里列出來,并用短一點的描述來代替,以簡化內(nèi)容。

左索引頁記錄數(shù),左端點記錄所在的索引頁中,從左端點記錄的下一條記錄開始,直到當(dāng)前索引頁中的 supremum

偽記錄的上一條記錄為止,這個范圍內(nèi)的記錄數(shù)量。

圖片

右索引頁記錄數(shù),右端點記錄所在的索引頁中,從當(dāng)前索引頁中的 infimum偽記錄的下一條記錄開始,直到右端點記錄的上一條記錄為止,這個范圍內(nèi)的記錄數(shù)量。

圖片

左右端點之間記錄數(shù),除了左端點記錄、右端點記錄之外,掃描區(qū)間中的其它用戶記錄的數(shù)量,也就是說,所有索引頁中的 infimum、supremum

偽記錄都不包含在內(nèi)。

圖片

(1) 同一條記錄

掃描區(qū)間左端點、右端點記錄是葉結(jié)點中的同一條記錄,除去左右端點記錄之外,區(qū)間之內(nèi)沒有其它記錄,左右端點之間記錄數(shù) = 0。

但是,這并不意味著掃描區(qū)間的記錄數(shù)量就為 0。

因為,掃描區(qū)間的記錄數(shù)量 = 左右端點之間的記錄數(shù) + 左端點記錄 + 右端點記錄。

處理左右端點記錄的計數(shù)邏輯,然后得到掃描區(qū)間記錄數(shù)量,這個計算過程是所有場景共用的,會在第 2 節(jié)的結(jié)尾處單獨用一個小節(jié)來介紹,這里先按下不表。

(2)同一個葉結(jié)點中的不同記錄

掃描區(qū)間左端點、右端點記錄是同一個葉結(jié)點中的不同記錄,計算邏輯也比較簡單。

左右端點之間記錄數(shù) = 右端點記錄之前的記錄數(shù)量 - 左端點記錄之前的記錄數(shù)量。

左右端點記錄之前的記錄數(shù)量,指的是它們共同所在的索引頁中,左右端點記錄各自前面有多少條記錄,如下圖所示:

圖片

(3)相鄰葉結(jié)點中的記錄

掃描區(qū)間左端點、右端點記錄是相鄰葉結(jié)點中的記錄,計算邏輯依然比較簡單。

左右端點之間記錄數(shù) = 左索引頁記錄數(shù) + 右索引頁記錄數(shù)。

圖片

(4)相隔小于等于 9 個葉結(jié)點

掃描區(qū)間左端點、右端點記錄所在的索引頁,中間隔著其它索引頁,計算邏輯開始變得有一點點復(fù)雜了。

左右端點之間記錄數(shù) = 左索引頁記錄數(shù) + 中間索引頁用戶記錄數(shù)之和 + 右索引頁記錄數(shù)。

圖片

上面算式中,中間索引頁用戶記錄數(shù)之和計算邏輯如下:

從掃描區(qū)間左端點記錄所在索引頁的下一個索引頁開始,從每個索引頁的頭信息 PAGE_N_RECS中讀取索引頁中的用戶記錄數(shù)量并累加求和,直到掃描區(qū)間右端點記錄所在索引頁的上一個索引頁為止。

PAGE_N_RECS 中不包含 infimum、supremum 偽記錄。

圖片

(5)相隔大于 9 個葉結(jié)點

前面幾個小節(jié)介紹的場景,計算掃描區(qū)間記錄數(shù)量的邏輯,都是精確計算。

本小節(jié)介紹的場景是:掃描區(qū)間左端點、右端點記錄所在的索引頁,中間隔著大于 9 個索引頁,如下圖所示:

圖片

此場景下,InnoDB不會讀取掃描區(qū)間內(nèi)所有索引頁中的用戶記錄數(shù)量,而是只讀取前面一部分索引頁中的用戶記錄數(shù)量,并據(jù)此估算出掃描區(qū)間內(nèi)的用戶記錄數(shù)量,估算過程是這樣的:

第 1 步,從掃描區(qū)間左端點記錄所在索引頁的下一個索引頁開始,連續(xù)讀取 9 個索引頁中的用戶記錄數(shù)量并累加求和。

每個索引頁中的用戶記錄數(shù)量都是從索引頁的頭信息 PAGE_N_RECS 中讀取,不包含 infimum、supremum 偽記錄。

第 2 步,第 1 步得到的 9 個索引頁的用戶記錄數(shù)量之和 + 左索引頁記錄數(shù) + 右索引頁記錄數(shù),得到計算結(jié)果,InnoDB 把這個結(jié)果當(dāng)作 10

個索引頁的用戶記錄數(shù)量之和。

圖片

第 3 步,第 2 步得到的10 個索引頁的用戶記錄數(shù)量之和,除以 10,得到的計算結(jié)果,作為掃描區(qū)間范圍內(nèi)每個索引頁的平均用戶記錄數(shù)。

第 4 步,第 3 步得到的平均用戶記錄數(shù) * 左右端點之間間隔的索引頁數(shù)(如下圖所示),得到間隔索引頁的用戶記錄數(shù)量之和。

圖片

左右端點記錄之間的索引頁數(shù),就是對上一層級進行 2.1 ~ 2.5 小節(jié)的計算邏輯得到。

第 5 步,左右端點之間記錄數(shù) = 第 4 步得到的左右端點記錄之間間隔索引頁的用戶記錄數(shù)量之和 + 左索引頁記錄數(shù) + 右索引頁記錄數(shù)。

圖片

前面說了在估算場景下,InnoDB 會用 10 個索引頁中的用戶記錄數(shù)量之和計算每個索引的平均用戶記錄數(shù)。

為什么本小節(jié)的標(biāo)題是左右端點之間相隔大于 9 個索引頁?

因為 InnoDB 把左索引頁記錄數(shù)、右索引頁記錄數(shù)加起來當(dāng)作一個索引頁的用戶記錄數(shù)量,再加上從掃描區(qū)間左端點記錄所在索引頁的下一個索引頁開始讀取的 9

個索引頁中的用戶記錄數(shù)量之和,就是 10 個索引頁的用戶記錄數(shù)量了。

(6) 處理左右端點記錄的計數(shù)邏輯

前面提到過,掃描區(qū)間的記錄數(shù)量 = 左右端點之間記錄數(shù) + 左端點記錄(0 或 1) + 右端點記錄(0 或 1)。

這是所有場景共用的邏輯,在這里單獨用一小節(jié)來介紹。

如果掃描區(qū)間左端點是閉區(qū)間(例如 WHERE a >= 100),則左端點記錄需要計入掃描區(qū)間的記錄數(shù)量,上面算式中,左端點記錄括號內(nèi)取

0。

否則不計入,上面算式中,左端點記錄括號內(nèi)取 1。

如果掃描區(qū)間右端點是閉區(qū)間(例如 WHERE a <= 200),則右端點記錄需要計入掃描區(qū)間的記錄數(shù)量,上面算式中,右端點記錄括號內(nèi)取

0。

否則不計入,上面算式中,右端點記錄括號內(nèi)取 1。

然后,就得到了掃描區(qū)間的記錄數(shù)量。

不過,別著急,這有可能還不是最終結(jié)果。

(7) 修正掃描區(qū)間記錄數(shù)量

經(jīng)過 2.6 小節(jié)中左右端點記錄的計數(shù)邏輯處理,已經(jīng)得到了掃描區(qū)間的記錄數(shù)量。

如果掃描區(qū)間左端點、右端點記錄所在的索引頁,中間隔著大于 9

個索引頁(也就是估算場景),計算得到掃描區(qū)間的記錄數(shù)量之后,還需要對這個數(shù)量進行一系列修正。

首先,InnoDB 認為估算的記錄數(shù)量都會比實際數(shù)量少,所以,會對前面計算得到的掃描區(qū)間記錄數(shù)量乘以 2,得到掃描區(qū)間的修正記錄數(shù)量,即修正記錄數(shù)量 =

掃描區(qū)間的記錄數(shù)量 * 2。

然后,InnoDB

不會讓估算記錄數(shù)量大于表中記錄數(shù)量的一半,如果掃描區(qū)間的修正記錄數(shù)量超過表中記錄數(shù)量的一半,就把修正記錄數(shù)量設(shè)置為表中記錄數(shù)量的一半。

最后,修改記錄數(shù)量就是掃描區(qū)間的記錄數(shù)量,這才是最終結(jié)果。

(8)小結(jié)

前面分場景介紹計算掃描區(qū)間的記錄數(shù)量的過程,為了保持文章盡量簡潔,把處理左右端點記錄的計數(shù)邏輯(2.6 小節(jié))、修正掃描區(qū)間記錄數(shù)量(2.7小節(jié))獨立成為兩個小節(jié),有一點零散。

本小節(jié)以一張流程圖來對前面的計算過程進行總結(jié),如下:

圖片

三、 總結(jié)

第 2 節(jié) 以定位索引葉結(jié)點中掃描區(qū)間左端點、右端點對應(yīng)的記錄開始,介紹了計算掃描區(qū)間記錄數(shù)量的整體過程。

第 3 節(jié) 根據(jù)索引葉結(jié)點中,左右端點記錄所在位置的不同,分 5 種場景介紹了計算掃描區(qū)間記錄數(shù)量的詳細過程。

經(jīng)過 5 種場景計算得到左右端點之間記錄數(shù)之后,再進行左右端點記錄的計數(shù)邏輯處理,得到掃描區(qū)間的記錄數(shù)量。

對于精確計算場景,這就是最終的結(jié)果了。

對于估算場景,還需要對掃描區(qū)間的記錄數(shù)量進行一系列修正,才能得到估算場景下的最終結(jié)果。

本文轉(zhuǎn)載自微信公眾號「一樹一溪」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系一樹一溪公眾號。

責(zé)任編輯:姜華 來源: 一樹一溪
相關(guān)推薦

2022-05-25 08:01:37

WHERESQL 語句

2010-10-12 16:50:14

MySQL Hash索

2023-01-26 00:59:39

B-Treegolang度量衡

2024-02-27 07:35:55

B-TreeB+TreeMySQL

2023-05-26 14:08:00

Where 條件MySQL

2023-01-30 23:04:10

B-Treegolang優(yōu)化

2022-10-29 08:44:39

分布式數(shù)據(jù)庫存儲

2022-03-07 14:57:36

MySQLInnoDB索引

2024-05-22 09:01:53

InnoDBB+索引

2024-09-04 08:44:18

MySQL核心模塊

2024-10-16 11:11:51

隔離InnoDB死鎖

2021-04-12 10:52:10

InnoDB索引數(shù)據(jù)庫

2018-08-26 06:24:58

MySQLInnoDB行鎖

2024-05-27 00:02:00

UpdateWhere索引

2025-06-16 07:45:00

2013-03-05 09:16:33

MySQLInnodb

2013-01-05 09:45:00

微軟Windows AzuCDN服務(wù)

2021-08-26 07:43:45

B+ 樹索引磁盤

2013-04-25 10:50:37

iCloud宕機

2020-05-19 20:45:27

MySQLref優(yōu)化器
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 亚洲一区久久久 | 亚洲天堂一区二区 | 国产欧美一区二区三区久久手机版 | 最新超碰 | 国产成人精品久久 | 亚洲国产一区二区视频 | 美女黄网站视频免费 | 亚洲精品久久久久久首妖 | 国产精品久久久久一区二区三区 | 一级片视频免费 | 国产精品久久国产精品 | 欧美精品首页 | 99精品99 | 一级毛片免费视频观看 | 日韩中文字幕第一页 | 日韩无| 亚洲视频在线看 | 久久亚洲综合 | 国产精品一区二区三区在线 | 国产成人精品综合 | 交专区videossex农村 | 亚洲午夜视频在线观看 | 91国产精品在线 | 久久99精品久久久久久国产越南 | 久草视频在线播放 | 成人国产精品久久久 | 国产精品毛片一区二区三区 | 中国美女av| 亚洲精品电影在线观看 | 欧美性生活视频 | 国产 欧美 日韩 一区 | 成人在线中文字幕 | 在线亚洲欧美 | www午夜视频 | 天天躁日日躁狠狠的躁天龙影院 | 日本在线视频一区二区 | 影音先锋欧美资源 | 成人免费观看视频 | 日韩欧美国产一区二区三区 | 久久久久久国产精品免费免费狐狸 | 欧美在线资源 |