原來知道有一些索引失效的條件,最近看了看mysql底層數據結構,明白了爲何會失效 ,記錄之。衆所周知,經常使用的mysql數據引擎有兩種,今天全是以InnoDB爲基礎開啓探索之旅的,另外一種有時間再說吧。mysql
咱們都知道,數據庫數據是存在磁盤中的,不過真正處理數據是在內存中進行的。這就須要從硬盤上不斷地把數據讀到內存中,因爲內存和磁盤速度差了好幾個數量級,因此爲了不頻繁交互帶來的性能問題,mysql一次會多讀取一些,是多少呢?讀一頁。一頁有16KB,也就是說一次讀取通常都是16KB的倍數。頁是硬盤內存交互的基本單位。sql
咱們平時所說的一條記錄叫數據行,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;
id name age 99 haha (null)
1 表示 這個屬性爲null,0表示這個屬性不爲null。因此name對應着0,age對應着1。因爲是倒敘存放的,因此 Null值列表 這個地方存放的是 10(age,name);性能
接下來就是真實數據了,值得一提的是,還有三個隱藏項:搜索引擎
如上圖所示,是一張數據頁內部結構。一個16KB的頁,內部存放着不少行,好比說那3條記錄,除此以外,內部存放着兩個特殊的記錄,最小記錄和最大記錄。數據頁內部記錄之間是以單鏈表的形式存放的,頭尾分別是那兩個特殊的記錄。在內存中有不少頁,頁和頁之間是用雙鏈表鏈接的。這樣方便快速定位到數據在哪一頁上。3d
ok,如今知道了數據頁、數據行,和它們之間的數據結構以後,就能夠看看咱們所謂的索引了。正如開頭所說的,這邊只介紹InnoDB的聚簇索引,另外一種搜索引擎,先不提它(嗯,如今甚至連名字都不提)。指針
聚簇索引,就是說有一顆樹,葉子節點就是真實數據行所構成的數據頁。code
通常爲了搜索快一點,咱們主鍵都是自動生成的(例如我們的User表),因此最下面那層是根據id排序生成的。最底下那層的葉子節點是真實的數據,有4頁,每頁裏面有一個單鏈表,就是咱們的真實數據行。第二行有兩頁,每頁中也是有個數據行構成的單鏈表,這是的數據行只包含了頁碼(最底下那層某頁)、某頁最大id,因而可知,第二行比最底下那行頁數少了不少不少。就這樣,一層一層的抽取,必定會有一個所謂的跟頁。咱們搜索數據就是從跟頁開始的,一層一層往下找的。因爲一個數據頁能夠存放16KB數據,因此三四層的樹狀圖就已經能存放不少不少數據了,因此不要擔憂樹會很深。再強調一下,頁內是單鏈表,同層的頁和頁之間是雙鏈表。blog
上面那是以主鍵爲搜索條件的索引,通常這棵樹是自動生成的。
咱們每每還會本身創建索引,好比給age添加索引。與聚簇索引相似,只不過葉子節點存的不是全部數據(而且根據age大小排序),而是存的該age屬性和主鍵id,非葉子節點寸的是頁碼和下面那層某頁最大的age值。這樣,你肯定了要搜的是哪些主鍵,還要回表(拿着這些主鍵回去聚簇索引找)去查詢真實的數據。這邊腦洞一下,即便你給age建立了索引,真正執行的時候,也不必定是經過查看二級索引,再回表的方式查數據(好比說經過二級索引搜索出來的是全部的id,再回表查詢,得不償失啊,還不如直接從聚簇索引直接去搜呢)。也可能根據聚簇索引直接搜索。具體採用哪一種方式mysql本身會評估。
還有種特殊的二級索引,聯合索引,好比說給(name、age)添加聯合索引,底層數據結構和普通二級索引沒什麼區別,只不過葉子節點存的不是全部數據(而且先根據name大小排序,name相同的狀況下再根據age排序),而是存的該name、age屬性和主鍵id,非葉子節點寸的是頁碼和下面那層某頁最大的name值。因此若是搜索條件只有age,沒有name的話,聯合索引會失效,因此要遵循最左原則。