mysql原理--B+樹索引

1.沒有索引的查找
1.1.在一個頁中的查找
(1). 以主鍵為搜索條件
可以在 頁目錄 中使用二分法快速定位到對應的槽,然后再遍歷該槽對應分組中的記錄即可快速找到指定的記錄。
(2). 以其他列作為搜索條件
這種情況下只能從 最小記錄 開始依次遍歷單鏈表中的每條記錄,然后對比每條記錄是不是符合搜索條件。

1.2.在很多頁中查找
(1). 定位到記錄所在的頁。
(2). 從所在的頁內中查找相應的記錄。

在沒有索引的情況下,不論是根據主鍵列或者其他列的值進行查找,由于我們并不能快速的定位到記錄所在的頁,所以只能從第一個頁沿著雙向鏈表一直往下找,在每一個頁中根據我們剛剛嘮叨過的查找方式去查找指定的記錄。

2.索引
以一個實例進行講解

mysql> CREATE TABLE index_demo(-> c1 INT,-> c2 INT,-> c3 CHAR(1),-> PRIMARY KEY(c1)-> ) ROW_FORMAT = Compact;

為了我們理解上的方便,我們簡化了一下 index_demo 表的行格式示意圖:
在這里插入圖片描述
在這里插入圖片描述
上述是一個簡略表示下的邏輯視圖。

2.1.一個簡單的索引方案
我們也可以想辦法為快速定位記錄所在的數據頁而建立一個別的目錄,建這個目錄必須完成下邊這些事兒:
(1). 下一個數據頁中用戶記錄的主鍵值必須大于上一個頁中用戶記錄的主鍵值。
為了故事的順利發展,我們這里需要做一個假設:假設我們的每個數據頁最多能存放3條記錄。
有了這個假設之后我們向 index_demo 表插入3條記錄:

 mysql> INSERT INTO index_demo VALUES(1, 4, 'u'), (3, 9, 'd'), (5, 3, 'y');

那么這些記錄已經按照主鍵值的大小串聯成一個單向鏈表了,如圖所示:
在這里插入圖片描述
此時我們再來插入一條記錄:

 mysql> INSERT INTO index_demo VALUES(4, 4, 'a');

因為 頁10 最多只能放3條記錄,所以我們不得不再分配一個新頁:
在這里插入圖片描述
再次強調一遍,新分配的數據頁編號可能并不是連續的,也就是說我們使用的這些頁在存儲空間里可能并不挨著。它們只是通過維護著上一個頁和下一個頁的編號而建立了鏈表關系。另外, 頁10 中用戶記錄最大的主鍵值是 5 ,而 頁28 中有一條記錄的主鍵值是 4 ,因為 5 > 4 ,所以這就不符合下一個數據頁中用戶記錄的主鍵值必須大于上一個頁中用戶記錄的主鍵值的要求,所以在插入主鍵值為 4 的記錄的時候需要伴隨著一次記錄移動,也就是把主鍵值為 5 的記錄移動到 頁28 中,然后再把主鍵值為 4 的記錄插入到 頁10 中,這個過程的示意圖如下:
在這里插入圖片描述
在這里插入圖片描述
這個過程表明了在對頁中的記錄進行增刪改操作的過程中,我們必須通過一些諸如記錄移動的操作來始終保證這個狀態一直成立:下一個數據頁中用戶記錄的主鍵值必須大于上一個頁中用戶記錄的主鍵值。這個過程我們也可以稱為 頁分裂 。

(2). 給所有的頁建立一個目錄項。
由于數據頁的編號可能并不是連續的,所以在向 index_demo 表中插入許多條記錄后,可能是這樣的效果:
在這里插入圖片描述
因為這些 16KB 的頁在物理存儲上可能并不挨著,所以如果想從這么多頁中根據主鍵值快速定位某些記錄所在的頁,我們需要給它們做個目錄,每個頁對應一個目錄項,每個目錄項包括下邊兩個部分:
a. 頁的用戶記錄中最小的主鍵值,我們用 key 來表示。
b. 頁號,我們用 page_no 表示。

所以我們為上邊幾個頁做好的目錄就像這樣子:
在這里插入圖片描述
我們只需要把幾個目錄項在物理存儲器上連續存儲,比如把他們放到一個數組里,就可以實現根據主鍵值快速查找某條記錄的功能了。比方說我們想找主鍵值為 20 的記錄,具體查找過程分兩步:
a. 先從目錄項中根據二分法快速確定出主鍵值為 20 的記錄在 目錄項3 中(因為 12 < 20 < 209 ),它對應的頁是 頁9 。
b. 再根據前邊說的在頁中查找記錄的方式去 頁9 中定位具體的記錄。

至此,針對數據頁做的簡易目錄就搞定了。不過忘了說了,這個 目錄 有一個別名,稱為 索引 。

2.2. InnoDB中的索引方案
上邊之所以稱為一個簡易的索引方案,是因為我們為了在根據主鍵值進行查找時使用二分法快速定位具體的目錄項而假設所有目錄項都可以在物理存儲器上連續存儲,但是這樣做有幾個問題:
(1). InnoDB 是使用頁來作為管理存儲空間的基本單位,也就是最多能保證 16KB 的連續存儲空間,而隨著表中記錄數量的增多,需要非常大的連續的存儲空間才能把所有的目錄項都放下,這對記錄數量非常多的表是不現實的。
(2). 我們時常會對記錄進行增刪,假設我們把 頁28 中的記錄都刪除了, 頁28 也就沒有存在的必要了,那意味著 目錄項2 也就沒有存在的必要了,這就需要把 目錄項2 后的目錄項都向前移動一下,這種牽一發而動全身的設計不是什么好主意~

他們復用了之前存儲用戶記錄的數據頁來存儲目錄項,為了和用戶記錄做一下區分,我們把這些用來表示目錄項的記錄稱為 目錄項記錄 。那 InnoDB 怎么區分一條記錄是普通的 用戶記錄 還是 目錄項記錄 呢?別忘了記錄頭信息里的 record_type 屬性,它的各個取值代表的意思如下:
0 :普通的用戶記錄
1 :目錄項記錄
2 :最小記錄
3 :最大記錄

我們把前邊使用到的目錄項放到數據頁中的樣子就是這樣:
在這里插入圖片描述
從圖中可以看出來,我們新分配了一個編號為 30 的頁來專門存儲 目錄項記錄 。這里再次強調一遍 目錄項記錄和普通的 用戶記錄 的不同點:
a. 目錄項記錄 的 record_type 值是1,而普通用戶記錄的 record_type 值是0。
b. 目錄項記錄 只有主鍵值和頁的編號兩個列,而普通的用戶記錄的列是用戶自己定義的,可能包含很多列,另外還有 InnoDB 自己添加的隱藏列。
c. 還記得我們之前在嘮叨記錄頭信息的時候說過一個叫 min_rec_mask 的屬性么,只有在存儲 目錄項記錄 的頁中的主鍵值最小的 目錄項記錄 的 min_rec_mask 值為 1 ,其他別的記錄的 min_rec_mask 值都是 0 。

除了上述幾點外,這兩者就沒啥差別了,它們用的是一樣的數據頁(頁面類型都是 0x45BF ,這個屬性在 File Header 中),頁的組成結構也是一樣一樣的(就是我們前邊介紹過的 7 個部分),都會為主鍵值生成 Page Directory (頁目錄),從而在按照主鍵值進行查找時可以使用二分法來加快查詢速度。

現在以查找主鍵為 20 的記錄為例,根據某個主鍵值去查找記錄的步驟就可以大致拆分成下邊兩步:
a. 先到存儲 目錄項記錄 的頁,也就是頁 30 中通過二分法快速定位到對應目錄項,因為 12 < 20 < 209 ,所以定位到對應的記錄所在的頁就是 頁9 。
b. 再到存儲用戶記錄的 頁9 中根據二分法快速定位到主鍵值為 20 的用戶記錄。

為了大家更好的理解新分配一個 目錄項記錄 頁的過程,我們假設一個存儲 目錄項記錄 的頁最多只能存放4條 目錄項記錄 。所以如果此時我們再向上圖中插入一條主鍵值為 320 的用戶記錄的話,那就需要分配一個新的存儲 目錄項記錄的頁嘍
在這里插入圖片描述
從圖中可以看出,我們插入了一條主鍵值為 320 的用戶記錄之后需要兩個新的數據頁:
a. 為存儲該用戶記錄而新生成了 頁31 。
b. 因為原先存儲 目錄項記錄 的 頁30 的容量已滿(我們前邊假設只能存儲4條 目錄項記錄 ),所以不得不需要一個新的 頁32 來存放 頁31 對應的目錄項。

現在因為存儲 目錄項記錄 的頁不止一個,所以如果我們想根據主鍵值查找一條用戶記錄大致需要3個步驟,以查找主鍵值為 20 的記錄為例:
a. 確定 目錄項記錄 頁
我們現在的存儲 目錄項記錄 的頁有兩個,即 頁30 和 頁32 ,又因為 頁30 表示的目錄項的主鍵值的范圍是[1, 320) , 頁32 表示的目錄項的主鍵值不小于 320 ,所以主鍵值為 20 的記錄對應的目錄項記錄在 頁30中。
b. 通過 目錄項記錄 頁確定用戶記錄真實所在的頁。
在一個存儲 目錄項記錄 的頁中通過主鍵值定位一條目錄項記錄的方式說過了,不贅述了~
c. 在真實存儲用戶記錄的頁中定位到具體的記錄。

在這個查詢步驟的第1步中我們需要定位存儲 目錄項記錄 的頁,但是這些頁在存儲空間中也可能不挨著,如果我們表中的數據非常多則會產生很多存儲 目錄項記錄 的頁,那我們怎么根據主鍵值快速定位一個存儲 目錄項記錄 的頁呢?

其實也簡單,為這些存儲 目錄項記錄 的頁再生成一個更高級的目錄,就像是一個多級目錄一樣,大目錄里嵌套小目錄,小目錄里才是實際的數據,所以現在各個頁的示意圖就是這樣子:
在這里插入圖片描述
如圖,我們生成了一個存儲更高級目錄項的 頁33 ,這個頁中的兩條記錄分別代表 頁30 和 頁32 ,如果用戶記錄的主鍵值在 [1, 320) 之間,則到 頁30 中查找更詳細的 目錄項記錄 ,如果主鍵值不小于 320 的話,就到 頁32中查找更詳細的 目錄項記錄 。隨著表中記錄的增加,這個目錄的層級會繼續增加,如果簡化一下,那么我們可以用下邊這個圖來描述它:
在這里插入圖片描述
其實這是一種組織數據的形式,或者說是一種數據結構,它的名稱是 B+ 樹。

不論是存放用戶記錄的數據頁,還是存放目錄項記錄的數據頁,我們都把它們存放到 B+ 樹這個數據結構中了,所以我們也稱這些數據頁為 節點 。從圖中可以看出來,我們的實際用戶記錄其實都存放在B+樹的最底層的節點上,這些節點也被稱為 葉子節點 或 葉節點 ,其余用來存放 目錄項 的節點稱為 非葉子節點 或者 內節點 ,其中 B+ 樹最上邊的那個節點也稱為 根節點 。

從圖中可以看出來,一個 B+ 樹的節點其實可以分成好多層,設計 InnoDB 的大叔們為了討論方便,規定最下邊的那層,也就是存放我們用戶記錄的那層為第 0 層,之后依次往上加。

假設所有存放用戶記錄的葉子節點代表的數據頁可以存放100條用戶記錄,所有存放目錄項記錄的內節點代表的數據頁可以存放1000條目錄項記錄,那么:
a. 如果 B+ 樹只有1層,也就是只有1個用于存放用戶記錄的節點,最多能存放 100 條記錄。
b. 如果 B+ 樹有2層,最多能存放 1000×100=100000 條記錄。
c. 如果 B+ 樹有3層,最多能存放 1000×1000×100=100000000 條記錄。
d. 如果 B+ 樹有4層,最多能存放 1000×1000×1000×100=100000000000 條記錄。

所以一般情況下,我們用到的 B+ 樹都不會超過4層,那我們通過主鍵值去查找某條記錄最多只需要做4個頁面內的查找(查找3個目錄項頁和一個用戶記錄頁),又因為在每個頁面內有所謂的 Page Directory (頁目錄),所以在頁面內也可以通過二分法實現快速定位記錄。

2.3. 聚簇索引
我們上邊介紹的 B+ 樹本身就是一個目錄,或者說本身就是一個索引。它有兩個特點:
(1). 使用記錄主鍵值的大小進行記錄和頁的排序,這包括三個方面的含義:
a. 頁內的記錄是按照主鍵的大小順序排成一個單向鏈表。
b. 各個存放用戶記錄的頁也是根據頁中用戶記錄的主鍵大小順序排成一個雙向鏈表。
c. 存放目錄項記錄的頁分為不同的層次,在同一層次中的頁也是根據頁中目錄項記錄的主鍵大小順序排成一個雙向鏈表。
(2). B+ 樹的葉子節點存儲的是完整的用戶記錄。
所謂完整的用戶記錄,就是指這個記錄中存儲了所有列的值(包括隱藏列)。

我們把具有這兩種特性的 B+ 樹稱為 聚簇索引 ,所有完整的用戶記錄都存放在這個 聚簇索引 的葉子節點處。這種 聚簇索引 并不需要我們在 MySQL 語句中顯式的使用 INDEX 語句去創建,InnoDB 存儲引擎會自動的為我們創建聚簇索引。另外有趣的一點是,在 InnoDB 存儲引擎中, 聚簇索引 就是數據的存儲方式(所有的用戶記錄都存儲在了 葉子節點 ),也就是所謂的索引即數據,數據即索引。

2.4. 二級索引
上邊介紹的 聚簇索引 只能在搜索條件是主鍵值時才能發揮作用,因為 B+ 樹中的數據都是按照主鍵進行排序的。

那如果我們想以別的列作為搜索條件該咋辦呢?
我們可以多建幾棵 B+ 樹,不同的 B+ 樹中的數據采用不同的排序規則。比方說我們用 c2 列的大小作為數據頁、頁中記錄的排序規則,再建一棵 B+ 樹,效果如下圖所示:
在這里插入圖片描述
這個 B+ 樹與上邊介紹的聚簇索引有幾處不同:
(1). 使用記錄 c2 列的大小進行記錄和頁的排序,這包括三個方面的含義:
a. 頁內的記錄是按照 c2 列的大小順序排成一個單向鏈表。
b. 各個存放用戶記錄的頁也是根據頁中記錄的 c2 列大小順序排成一個雙向鏈表。
c. 存放目錄項記錄的頁分為不同的層次,在同一層次中的頁也是根據頁中目錄項記錄的 c2 列大小順序排成一個雙向鏈表。
(2). B+ 樹的葉子節點存儲的并不是完整的用戶記錄,而只是 c2列+主鍵 這兩個列的值。
(3). 目錄項記錄中不再是 主鍵+頁號 的搭配,而變成了 c2列+頁號 的搭配。

所以如果我們現在想通過 c2 列的值查找某些記錄的話就可以使用我們剛剛建好的這個 B+ 樹了。以查找 c2 列的值為 4 的記錄為例,查找過程如下:
(1). 確定 目錄項記錄 頁
根據 根頁面 ,也就是 頁44 ,可以快速定位到 目錄項記錄 所在的頁為 頁42 (因為 2 < 4 < 9 )。
(2). 通過 目錄項記錄 頁確定用戶記錄真實所在的頁。
在 頁42 中可以快速定位到實際存儲用戶記錄的頁,但是由于 c2 列并沒有唯一性約束,所以 c2 列值為 4 的記錄可能分布在多個數據頁中,又因為 2 < 4 ≤ 4 ,所以確定實際存儲用戶記錄的頁在 頁34 和 頁35 中。
(3). 在真實存儲用戶記錄的頁中定位到具體的記錄。
到 頁34 和 頁35 中定位到具體的記錄。
(4). 但是這個 B+ 樹的葉子節點中的記錄只存儲了 c2 和 c1 (也就是 主鍵 )兩個列,所以我們必須再根據主鍵值去聚簇索引中再查找一遍完整的用戶記錄。

我們根據這個以 c2 列大小排序的 B+ 樹只能確定我們要查找記錄的主鍵值,所以如果我們想根據 c2 列的值查找到完整的用戶記錄的話,仍然需要到 聚簇索引 中再查一遍,這個過程也被稱為 回表 。也就是根據 c2 列的值查詢一條完整的用戶記錄需要使用到 2 棵 B+ 樹!!!

為什么我們還需要一次 回表 操作呢?直接把完整的用戶記錄放到 葉子節點 不就好了么?
如果把完整的用戶記錄放到 葉子節點 是可以不用 回表 ,但是太占地方了呀~相當于每建立一棵 B+ 樹都需要把所有的用戶記錄再都拷貝一遍,這就有點太浪費存儲空間了。因為這種按照 非主鍵列 建立的 B+ 樹需要一次 回表 操作才可以定位到完整的用戶記錄,所以這種 B+ 樹也被稱為 二級索引 (英文名 secondary index ),或者 輔助索引 。由于我們使用的是 c2 列的大小作為 B+ 樹的排序規則,所以我們也稱這個 B+ 樹為為c2列建立的索引。

2.5. 聯合索引
我們也可以同時以多個列的大小作為排序規則,也就是同時為多個列建立索引,比方說我們想讓 B+ 樹按照 c2 和 c3 列的大小進行排序,這個包含兩層含義:
(1). 先把各個記錄和頁按照 c2 列進行排序。
(2). 在記錄的 c2 列相同的情況下,采用 c3 列進行排序

為 c2 和 c3 列建立的索引的示意圖如下:
在這里插入圖片描述
如圖所示,我們需要注意一下幾點:
(1). 每條 目錄項記錄 都由 c2 、 c3 、 頁號 這三個部分組成,各條記錄先按照 c2 列的值進行排序,如果記錄的 c2 列相同,則按照 c3 列的值進行排序。
(2). B+ 樹葉子節點處的用戶記錄由 c2 、 c3 和主鍵 c1 列組成。

千萬要注意一點,以c2和c3列的大小為排序規則建立的B+樹稱為聯合索引,本質上也是一個二級索引。它的意思與分別為c2和c3列分別建立索引的表述是不同的,不同點如下:
(1). 建立 聯合索引 只會建立如上圖一樣的1棵 B+ 樹。
(2). 為c2和c3列分別建立索引會分別以 c2 和 c3 列的大小為排序規則建立2棵 B+ 樹。

2.6. InnoDB的B+樹索引的注意事項
2.6.1. 根頁面萬年不動窩
我們前邊介紹 B+ 樹索引的時候,為了大家理解上的方便,先把存儲用戶記錄的葉子節點都畫出來,然后接著畫存儲目錄項記錄的內節點,實際上 B+ 樹的形成過程是這樣的:
(1). 每當為某個表創建一個 B+ 樹索引(聚簇索引不是人為創建的,默認就有)的時候,都會為這個索引創建一個 根節點 頁面。最開始表中沒有數據的時候,每個 B+ 樹索引對應的 根節點 中既沒有用戶記錄,也沒有目錄項記錄。
(2). 隨后向表中插入用戶記錄時,先把用戶記錄存儲到這個 根節點 中。
(3). 當 根節點 中的可用空間用完時繼續插入記錄,此時會將 根節點 中的所有記錄復制到一個新分配的頁,比如 頁a 中,然后對這個新頁進行 頁分裂 的操作,得到另一個新頁,比如 頁b 。這時新插入的記錄根據鍵值(也就是聚簇索引中的主鍵值,二級索引中對應的索引列的值)的大小就會被分配到 頁a 或者 頁b 中,而根節點 便升級為存儲目錄項記錄的頁。

這個過程需要大家特別注意的是:一個B+樹索引的根節點自誕生之日起,便不會再移動。這樣只要我們對某個表建立一個索引,那么它的 根節點 的頁號便會被記錄到某個地方,然后凡是 InnoDB 存儲引擎需要用到這個索引的時候,都會從那個固定的地方取出 根節點 的頁號,從而來訪問這個索引。

2.6.2.內節點中目錄項記錄的唯一性
我們知道 B+ 樹索引的內節點中目錄項記錄的內容是 索引列 + 頁號 的搭配,但是這個搭配對于二級索引來說有點兒不嚴謹。還拿 index_demo 表為例,假設這個表中的數據是這樣的:
在這里插入圖片描述
如果二級索引中目錄項記錄的內容只是 索引列 + 頁號 的搭配的話,那么為 c2 列建立索引后的 B+ 樹應該長這樣:
在這里插入圖片描述
如果我們想新插入一行記錄,其中 c1 、 c2 、 c3 的值分別是: 9 、 1 、 ‘c’ ,那么在修改這個為 c2 列建立的二級索引對應的 B+ 樹時便碰到了個大問題:
由于 頁3 中存儲的目錄項記錄是由 c2列 + 頁號 的值構成的,頁3 中的兩條目錄項記錄對應的 c2 列的值都是 1 ,而我們新插入的這條記錄的 c2 列的值也是 1 ,那我們這條新插入的記錄到底應該放到 頁4 中,還是應該放到 頁5 中啊?答案是:對不起,懵逼了。

為了讓新插入記錄能找到自己在那個頁里,我們需要保證在B+樹的同一層內節點的目錄項記錄除 頁號 這個字段以外是唯一的。所以對于二級索引的內節點的目錄項記錄的內容實際上是由三個部分構成的:
a. 索引列的值
b. 主鍵值
c. 頁號

也就是我們把 主鍵值 也添加到二級索引內節點中的目錄項記錄了,這樣就能保證 B+ 樹每一層節點中各條目錄項記錄除 頁號 這個字段外是唯一的,所以我們為 c2 列建立二級索引后的示意圖實際上應該是這樣子的:
在這里插入圖片描述
這樣我們再插入記錄 (9, 1, ‘c’) 時,由于 頁3 中存儲的目錄項記錄是由 c2列 + 主鍵 + 頁號 的值構成的,可以先把新記錄的 c2 列的值和 頁3 中各目錄項記錄的 c2 列的值作比較,如果 c2 列的值相同的話,可以接著比較主鍵值,因為 B+ 樹同一層中不同目錄項記錄的 c2列 + 主鍵 的值肯定是不一樣的,所以最后肯定能定位唯一的一條目錄項記錄,在本例中最后確定新記錄應該被插入到 頁5 中。

2.6.3. 一個頁面最少存儲2條記錄
我們前邊說過一個B+樹只需要很少的層級就可以輕松存儲數億條記錄,查詢速度杠杠的!這是因為B+樹本質上就是一個大的多層級目錄,每經過一個目錄時都會過濾掉許多無效的子目錄,直到最后訪問到存儲真實數據的目錄。InnoDB 的一個數據頁至少可以存放兩條記錄,這也是我們之前嘮叨記錄行格式的時候說過一個結論。

2.7.MyISAM中的索引方案簡單介紹
MyISAM 的索引方案雖然也使用樹形結構,但是卻將索引和數據分開存儲:
(1). 將表中的記錄按照記錄的插入順序單獨存儲在一個文件中,稱之為 數據文件 。這個文件并不劃分為若干個數據頁,有多少記錄就往這個文件中塞多少記錄就成了。我們可以通過行號而快速訪問到一條記錄。MyISAM 記錄也需要記錄頭信息來存儲一些額外數據,我們以上邊嘮叨過的 index_demo 表為例,看一下這個表中的記錄使用 MyISAM 作為存儲引擎在存儲空間中的表示:
在這里插入圖片描述
由于在插入數據的時候并沒有刻意按照主鍵大小排序,所以我們并不能在這些數據上使用二分法進行查找。

(2). 使用 MyISAM 存儲引擎的表會把索引信息另外存儲到一個稱為 索引文件 的另一個文件中。MyISAM 會單獨為表的主鍵創建一個索引,只不過在索引的葉子節點中存儲的不是完整的用戶記錄,而是 主鍵值 + 行號 的組合。也就是先通過索引找到對應的行號,再通過行號去找對應的記錄!

在 InnoDB 存儲引擎中,我們只需要根據主鍵值對 聚簇索引 進行一次查找就能找到對應的記錄,而在 MyISAM 中卻需要進行一次 回表 操作,意味著 MyISAM 中建立的索引相當于全部都是 二級索引 !

(3).如果有需要的話,我們也可以對其它的列分別建立索引或者建立聯合索引,原理和 InnoDB 中的索引差不多,不過在葉子節點處存儲的是 相應的列 + 行號 。這些索引也全部都是 二級索引 。

上邊用到的index_demo表采用定長記錄格式,也就是一條記錄占用存儲空間的大小是固定的,這樣就可以通過行號輕松算出某條記錄在數據文件中的地址偏移量。但是變長記錄格式就不行了,MyISAM會直接在索引葉子節點處存儲該條記錄在數據文件中的地址偏移量。通過這個可以看出,MyISAM的回表操作是十分快速的,因為是拿著地址偏移量直接到文件中取數據的,反觀InnoDB是通過獲取主鍵之后再去聚簇索引里邊兒找記錄,雖然說也不慢,但還是比不上直接用地址去訪問。

3.MySQL中創建和刪除索引的語句
InnoDB 和 MyISAM 會自動為主鍵或者聲明為 UNIQUE 的列去自動建立 B+ 樹索引,但是如果我們想為其他的列建立索引就需要我們顯式的去指明。每建立一個索引都會建立一棵 B+ 樹,每插入一條記錄都要維護各個記錄、數據頁的排序關系,這是很費性能和存儲空間的。

我們可以在創建表的時候指定需要建立索引的單個列或者建立聯合索引的多個列:

CREATE TALBE 表名 (各種列的信息 ··· , [KEY|INDEX] 索引名 (需要被索引的單個列或多個列)
)

其中的 KEY 和 INDEX 是同義詞,任意選用一個就可以。我們也可以在修改表結構的時候添加索引:

ALTER TABLE 表名 ADD [INDEX|KEY] 索引名 (需要被索引的單個列或多個列);

也可以在修改表結構的時候刪除索引:

ALTER TABLE 表名 DROP [INDEX|KEY] 索引名;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/215873.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/215873.shtml
英文地址,請注明出處:http://en.pswp.cn/news/215873.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

值得收藏的練習打字網站

本文對一些好用的練習打字的網站進行了匯總整理&#xff0c;方便大家使用 一&#xff1a;程序猿練習打字&#xff1a; 1.Typing Practice for Programmers http://Typing.io 是程序員的打字導師。它的練習課程基于開源代碼&#xff0c;讓你在不斷的練習中提升自己的碼字速度…

Python:核心知識點整理大全15-筆記

目錄 ?編輯 7.3.2 刪除包含特定值的所有列表元素 pets.py 7.3.3 使用用戶輸入來填充字典 mountain_poll.py 7.4 小結 第8章 函 數 8.1 定義函數 greeter.py 8.1.1 向函數傳遞信息 8.1.2 實參和形參 8.2.1 位置實參 2. 位置實參的順序很重要 8.2.2 關鍵字實參 往…

Ansible通過kubernetes.core.k8s_info和kubernetes.core.k8s訪問OCP

文章目錄 環境OCPClient&#xff08;Ansible控制節點&#xff09; 步驟準備工作在client端配置ssh免密登錄OCP端在client端安裝Ansible kubernetes.core.k8s_info第1次嘗試在OCP端安裝python和pip3在OCP端安裝kubernetes在OCP端安裝PyYAML第2次嘗試在OCP端配置config文件第3次嘗…

計算機循環神經網絡(RNN)

計算機循環神經網絡&#xff08;RNN&#xff09; 一、引言 循環神經網絡&#xff08;RNN&#xff09;是一種常見的深度學習模型&#xff0c;適用于處理序列數據&#xff0c;如文本、語音、時間序列等。RNN通過捕捉序列數據中的時間依賴關系和上下文信息&#xff0c;能夠解決很…

react Hooks之useId

當我們在編寫React組件時&#xff0c;有時需要為元素生成唯一的ID。這種情況經常出現在表單元素、標簽和用于無障礙性的目的上。React提供了一個名為useId的自定義Hook&#xff0c;它可以幫助我們生成唯一的ID。 1、作用&#xff1a; 用于生成一個唯一的 ID。這個 ID 可以用于…

CLIP的升級版Alpha-CLIP:區域感知創新與精細控制

為了增強CLIP在圖像理解和編輯方面的能力&#xff0c;上海交通大學、復旦大學、香港中文大學、上海人工智能實驗室、澳門大學以及MThreads Inc.等知名機構共同合作推出了Alpha-CLIP。這一創新性的突破旨在克服CLIP的局限性&#xff0c;通過賦予其識別特定區域&#xff08;由點、…

Could not resolve all dependencies for configuration ‘:app:androidApis‘.

android studio出現Could not resolve all dependencies for configuration ‘:app:androidApis’. 試過很多種方法&#xff0c;但是都不好使&#xff0c;不管怎么樣都是提示如下報錯&#xff1a; Using insecure protocols with repositories, without explicit opt-in, is un…

丹麥市場開發攻略,帶你走進童話王國

說起安徒生&#xff0c;大家多多少少都知道&#xff0c;因為小時候讀的安徒生童話書真的太有名了&#xff0c;但是大家可能不知道安徒生是丹麥的。丹麥是高度發達的國家&#xff0c;奉行自由貿易政策&#xff0c;市場潛力是非常不錯的&#xff0c;而且中國是丹麥非常重要的貿易…

Python部分基礎知識入門學習,十分鐘快速上手

文章目錄 一、基礎語法二、變量類型三、運算符四、條件語句關于Python技術儲備一、Python所有方向的學習路線二、Python基礎學習視頻三、精品Python學習書籍四、Python工具包項目源碼合集①Python工具包②Python實戰案例③Python小游戲源碼五、面試資料六、Python兼職渠道 一、…

這家消金公司業務調整,暫停合作產品貸款服務

來源 | 鐳射財經&#xff08;leishecaijing&#xff09; 曾為金美信重要的線上自營渠道之一&#xff0c;錢多美宣告謝幕。 「鐳射財經」注意到&#xff0c;金美信消費金融近期發布一則關于錢多美的業務調整公告&#xff0c;提及2023年12月15日起&#xff0c;旗下“錢多美App”…

初識 WebGPU 以及遇到 WebGPU not supported 錯誤的解決方法

初識 WebGPU 以及遇到 WebGPU not supported 錯誤的解決方法 WebGPU學習資源初識WebGPU遇到并解決問題在線示例 因公司需求&#xff0c;開始接觸 WebGPU&#xff0c;偶然遇到問題&#xff0c;網上搜索無效&#xff0c;后來通過逐步判斷&#xff0c;終于定位到問題&#xff0c;這…

【WPF 按鈕點擊后異步上傳多文件code示例】

前言: WPF中按鈕點擊事件如何執行時間太長會導致整個UI線程卡頓&#xff0c;現象就是頁面刷新卡住&#xff0c;點擊其他按鈕無反饋。如下是進行異步執行命令&#xff0c;并遠程上傳文件的代碼。 ![異步上傳文件](https://img-blog.csdnimg.cn/direct/20c071929b004dcf9223dee2…

聽我的,日志還是得好好打!

日志這東西&#xff0c;平時看不出來什么&#xff0c;真要出了問題&#xff0c;那就是救命的稻草。這期就給大家分享一些日志相關的東西。 弄懂日志 SpringBoot項目啟動日志 什么是日志&#xff1f; 日志&#xff0c;維基百科中對其的定義是一個或多個由服務器自動創建和維護…

【數學建模】《實戰數學建模:例題與講解》第十一講-因子分析、聚類與主成分(含Matlab代碼)

【數學建模】《實戰數學建模&#xff1a;例題與講解》第十一講-因子分析、聚類與主成分&#xff08;含Matlab代碼&#xff09; 基本概念聚類分析Q型聚類分析R型聚類分析 主成分分析因子分析 習題10.11. 題目要求2.解題過程3.程序4.結果 習題10.21. 題目要求2.解題過程3.程序4.結…

Java網絡編程——安全網絡通信

在網絡上&#xff0c;信息在由源主機到目標主機的傳輸過程中會經過其他計算機。在一般情況下&#xff0c;中間的計算機不會監聽路過的信息。但在使用網上銀行或者進行信用卡交易時&#xff0c;網絡上的信息有可能被非法分子監聽&#xff0c;從而導致個人隱私的泄露。由于Intern…

request、limit資源配額

cpu/mem 的limit和request都是針對container來講的&#xff0c;不是針對pod。 0 < request < limit cpu cpu資源限制的單位m&#xff1a;CPU的計量單位叫毫核(m)。一個節點的CPU核心數量乘以1000&#xff0c;得到的就是節點總的CPU總數量。如&#xff0c;一個節點有兩個…

Rust做一個圖片服務器有多難?

今天我們將詳細探討如何使用Rust構建一個圖片服務器。Rust以其性能、安全性和并發處理能力而聞名&#xff0c;非常適合用于構建網絡服務。 一個圖片服務器需要處理圖片的上傳、存儲、訪問和處理&#xff0c;同時還要考慮安全性和性能。讓我們一步步了解如何用Rust來實現這一目…

使用kubeadm搭建高可用的K8s集群

—————————————————————————————————————————————— 博主介紹&#xff1a;Java領域優質創作者,博客之星城市賽道TOP20、專注于前端流行技術框架、Java后端技術領域、項目實戰運維以及GIS地理信息領域。 &#x1f345;文末獲取源碼…

ImmunityCanvas7.26安裝詳細教程

ImmunityCanvas7.26 大家想必都已經知道了Immunity Canvas7.26武器于2021年3月2日泄露了吧那我就廢話不多說了。 很多人已經有了這款工具不得不說這工具很nice如果要買的話一年的話3萬美金我的天我窮了。。 簡單介紹 Immunity Canvas是美國ImmunitySec出品的安全漏洞檢測工具…

數據庫產品層出不窮,金融行業應該怎么選?|飛輪科技聯合創始人連林江

眾所周知&#xff0c;金融行業對于數據有著極為嚴苛的標準和要求&#xff0c;尤其當在線化、實時化業務場景增多以后&#xff0c;金融行業也面臨著多重的挑戰&#xff1a;既要滿足實時數據分析的高性能、高效率需求&#xff0c;又要確保數據的安全性和完整性。基于此&#xff0…