【mysql學習】InnoDB數據結構


原來知道有一些索引失效的條件,最近看了看mysql底層數據結構,明白了為什么會失效 ,記錄之。眾所周知,常用的mysql數據引擎有兩種,今天全是以InnoDB為基礎開啟探索之旅的,另一種有時間再說吧。

數據頁與數據行

我們都知道,數據庫數據是存在磁盤中的,不過真正處理數據是在內存中進行的。這就需要從硬盤上不斷地把數據讀到內存中,由於內存和磁盤速度差了好幾個數量級,所以為了避免頻繁交互帶來的性能問題,mysql一次會多讀取一些,是多少呢?讀一頁。一頁有16KB,也就是說一次讀取一般都是16KB的倍數。頁是硬盤內存交互的基本單位。

我們平時所說的一條記錄叫數據行,InnoDB有四種不同類型的數據行,Compact、Redundant、Dynamic和Compressed。主要介紹下Compact

為了方便后面說明,建個表:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `age` smallint(3) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8;

數據行結構

  • 變長字段長度列表:類似於varchar() 這種可變長度,記錄某個屬性的長度,方便快速讀取某屬性的值。長度值是倒敘存放的。
  • Null值列表:記錄可為空的那些值,是否為空。
    為了方便說明舉例:
id	name	age
99	haha	(null)

1 表示 這個屬性為null,0表示這個屬性不為null。所以name對應着0,age對應着1。由於是倒敘存放的,所以 Null值列表 這個地方存放的是 10(age,name);

  • 記錄頭信息
    數據有很多,關鍵的:
    delete_mask:標記該記錄是否被刪除
    record_type:表示當前記錄的類型,0表示普通記錄,1表示B+樹非葉子節點記錄,2表示最小記錄,3表示最大記錄。

接下來就是真實數據了,值得一提的是,還有三個隱藏項

  1. row_id:如果沒有主鍵ID,數據庫會自動生成一個行的標識ID。所以這個值是可選的。
  2. transaction_id:事務ID
  3. roll_pointer:回滾指針。

頁行關系

數據頁內部結構
如上圖所示,是一張數據頁內部結構。一個16KB的頁,內部存放着很多行,比如說那3條記錄,除此之外,內部存放着兩個特殊的記錄,最小記錄最大記錄。數據頁內部記錄之間是以單鏈表的形式存放的,頭尾分別是那兩個特殊的記錄。在內存中有很多頁,頁和頁之間是用雙鏈表連接的。這樣方便快速定位到數據在哪一頁上。

B+ 索引

聚簇索引

ok,現在知道了數據頁、數據行,和它們之間的數據結構之后,就可以看看我們所謂的索引了。正如開頭所說的,這邊只介紹InnoDB的聚簇索引,另一種搜索引擎,先不提它(嗯,現在甚至連名字都不提)。

聚簇索引,就是說有一顆樹,葉子節點就是真實數據行所構成的數據頁。

聚簇索引
一般為了搜索快一點,我們主鍵都是自動生成的(例如咱們的User表),所以最下面那層是根據id排序生成的。最底下那層的葉子節點是真實的數據,有4頁,每頁里面有一個單鏈表,就是我們的真實數據行。第二行有兩頁,每頁中也是有個數據行構成的單鏈表,這是的數據行只包含了頁碼(最底下那層某頁)、某頁最大id,由此可見,第二行比最底下那行頁數少了很多很多。就這樣,一層一層的抽取,一定會有一個所謂的跟頁。我們搜索數據就是從跟頁開始的,一層一層往下找的。由於一個數據頁可以存放16KB數據,所以三四層的樹狀圖就已經能存放很多很多數據了,所以不要擔心樹會很深。再強調一下,頁內是單鏈表,同層的頁和頁之間是雙鏈表。

二級索引

上面那是以主鍵為搜索條件的索引,一般這棵樹是自動生成的。

我們往往還會自己建立索引,比如給age添加索引。與聚簇索引類似,只不過葉子節點存的不是所有數據(並且根據age大小排序),而是存的該age屬性和主鍵id,非葉子節點寸的是頁碼和下面那層某頁最大的age值。這樣,你確定了要搜的是哪些主鍵,還要回表(拿着這些主鍵回去聚簇索引找)去查詢真實的數據。這邊腦洞一下,即使你給age創建了索引,真正執行的時候,也不一定是通過查看二級索引,再回表的方式查數據(比如說通過二級索引搜索出來的是所有的id,再回表查詢,得不償失啊,還不如直接從聚簇索引直接去搜呢)。也可能根據聚簇索引直接搜索。具體采用哪種方式mysql自己會評估。

聯合索引

還有種特殊的二級索引,聯合索引,比如說給(name、age)添加聯合索引,底層數據結構和普通二級索引沒什么區別,只不過葉子節點存的不是所有數據(並且先根據name大小排序,name相同的情況下再根據age排序),而是存的該name、age屬性和主鍵id,非葉子節點寸的是頁碼和下面那層某頁最大的name值。所以如果搜索條件只有age,沒有name的話,聯合索引會失效,所以要遵循最左原則。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM