MySQL索引原理

2021-10-04 06:35:37 字數 3214 閱讀 3859

mysql表的資料是儲存在磁碟上的,索引資料也是儲存在磁碟上,當使用myisam引擎時,建立表會在磁碟上生成三個檔案,.frm儲存表結構,.myi儲存索引,myd儲存表資料,而使用innodb引擎時,雖然我們看不到myi檔案了,其實它是將索引和資料都存在了myd檔案中。

要想搞清楚mysql索引的原理,必須先搞作業系統讀取從磁碟讀取檔案的原理,大概就是根據磁碟資料位址指標旋轉磁碟到指定扇區,移動磁頭到指定扇道,然後將資料載入到記憶體。尋道的時間相比於cpu從記憶體讀取資料的時間要慢的多,不在乙個數量級。我們要想提高查詢效率,必須從減少尋道次數入手。

計算機中有乙個最近原則,就是當前使用的資料緊鄰的資料有很大的可能會在下一時刻被使用到,所以在作業系統層面對讀取資料的過程做了優化,就是每次不唯讀當前需要的資料,與其相鄰的資料也會載入到記憶體,具體就是一次載入一頁資料,一頁資料一般為4k。

msyql在作業系統優化的基礎上做進一步優化,定義自己頁的概念,一次載入更多的時間,同時使用b+樹的資料結構進一步提公升查詢速度。

致於為什麼使用b+樹,而不使用其他資料結構,可參考另一篇分析文章 b樹、b+樹的分析及應用

innodb主鍵索引

innodb中主鍵索引儲存示意圖如下

作業系統在儲存資料時,是以頁為單位的,每次讀取最小單位就是一頁,一般4k為一頁,根頁、索引頁、資料頁都是作業系統的一頁,大小是一樣的。

mysql儲存也有頁的概念,一次讀取就是mysql的一頁,頁的大小通過引數innodb_page_size控制,預設大小為16k

儲存示意圖中data的占用空間的大小就是表中一行的長度(所有列長度相加),key占用空間就是主鍵占用長度。

假如key為長整型(bigint)佔8個位元組,data的佔200個位元組,這樣一行共佔8+200=208個位元組,作業系統一頁可存行數4*1024/208=20行,所以mysql的一頁儲存4*20=80行。

對於索引頁key還是bigint型別,佔8個位元組,point為指標,占用6個位元組,這樣msyql一頁儲存的【key+point】鍵值對個數為16384/(8+6)=1170。根據b+樹的概念,這就相當於乙個1170階的b+樹,而乙個節點可有子節點個數為1170+1 = 1171

假如b+樹的高度為2,即只有乙個根節點,下面掛的就是葉子節點,這樣能儲存的資料行數為1170*1171*20 = 2740,1400,而假如b+樹的高度為3,則儲存的資料行數為1170*1171*1171*20 = 320,5960,0000

一般情況一行資料佔200位元組可能偏少,假如我們按照1k來算

b+樹高度為2時,儲存行數為:1170*1171 = 137,0070

b+樹高度為3時,儲存行數為:1170*1171*1171 = 16,0435,2000

樹的高度就相當於查詢時的io次數,而mysql又將根頁快取到了記憶體中,所以真正io次數比高度小1,所以當我們使用主鍵去查詢時,表資料小於137,0070條時,一次io就可以查詢到,表資料小於16,0435,2000條時兩次io就能查詢到,可見通過主鍵查詢時是非常快的。

面試的時候有時會為什麼mysql主鍵用自增而不用uuid,主要有兩方面:

第一是由b+的屬性決定的,b+樹不管是索引頁還是資料頁中的key都是按照順序排列的,而uuid是無序的,這樣就會導致大量的資料在資料頁遷移,同時導致索引頁重構,如果採用自增主鍵,新產生的key總是比之前的大,資料頁只要依次新增資料即可,不會有遷移的情況,索引頁也是依次產生,不會有重構

第二,uuid佔32位元組,bigint佔8位元組,如果使用uuid,索引頁存放【key+point】鍵值對個數為16384/(32+6)= 431,比1170小的多,也就表示需要更多的頁來儲存相同量的資料,從而導致樹的高度增加,io次數增加,耗時增加。

innodb非主鍵單個索引

單個索引儲存示意圖

從圖中可看出在根頁和索引頁儲存的為【index+point】,index即為我們索引列的值,資料頁儲存的並不像主鍵索引那樣為行資料而是資料行中的主鍵值。這樣通過這個索引查資料時,就需要先查詢出滿足條件的所有主鍵,然後再通過主鍵索引查詢出所需資料。這個過程就是回表,不過需要注意一下,如果selec查詢的列只有索引列,是不需要回表的,因為當前索引樹中已經儲存了此列的所有值。

之所以為什麼要這樣儲存,我們可以想一下,如果不這樣儲存,而像主鍵索引一樣儲存資料會怎麼樣。

1、全表資料會在每個索引樹中儲存乙份,有多少個索引就會有多少份全表資料,造成空間的浪費

2、當表資料修改時,就需要把每個索引中的資料一併給修改了,並且是事物操作,太影響效能

innodb非主鍵組合索引

組合索引儲存示意圖

此時索引儲存的即是多個列的拼接值,由此就可理解我們在sql查詢的時候為什麼有最左原則,還有在使用like '***%' 時能夠走索引也是同樣的道理。

從非主鍵索引的儲存結構示意圖中也可發現bigint型別的自增主鍵比uuid要節省儲存空間。也可發現使用innodb時為什麼必須要有主鍵,當我們使用innodb建立的表沒有指定主鍵時,mysql會使用建立了唯一索引的列作為主鍵,如果我們也沒有建立唯一索引,mysql會使用隱藏的rowid列作為主鍵,總之必須要有乙個主鍵,這樣非主鍵型別的索引才可引用。

myisam索引

由於使用myisam引擎時,資料和索引是分開儲存的,不會像innodb主鍵索引那樣,在b+樹的葉子節點儲存主鍵+資料,而是像innodb的非主鍵索引那樣儲存,只不過葉子節點不儲存主鍵key,而是儲存資料所在的磁碟位置的指標。

索引的開銷

從上面的分析可想而知,有了索引後會占用一部分磁碟空間,並且我們對錶的索引列進行增刪改操作時,索引檔案也會跟著變更,這樣會對我們的增刪改操作有一定的效能影響,所以並不是索引越多越好,我們要根據需求適量的建立索引。

MySQL索引原理之索引原理

索引定義 是儲存引擎用於快速查詢記錄的一種資料結構。需要額外開闢空間和資料維護工作。索引是物理資料頁儲存,在資料檔案中 innodb,ibd檔案 利用資料頁 page 儲存。索引可以加快檢索速度,但是同時也會降低增刪改操作速度,索引維護需要代價。索引涉及的理論知識 二分查詢法 hash和b tree...

mysql索引 mysql索引實現原理

什麼是索引 索引是一種高效獲取資料的儲存結構,例 hash 二叉 紅黑。mysql為什麼不用上面三種資料結構而採用b tree 若僅僅是 select from table where id 45 上面三種演算法可以輕易實現,但若是select from table where id 6 就不好使了...

mysql 索引原理

b樹 b樹高度 資料庫為什麼使用這種結構?一般來說,索引本身也很大,不可能全部儲存在記憶體中,因此索引往往以索引檔案的形式儲存的磁碟上。這樣的話,索引查詢過程中就要產生磁碟i o消耗,相對於記憶體訪問,i o訪問的消耗要高幾個數量級,所以評價乙個資料結構作為索引的優劣最重要的指標就是在查詢過程中磁碟...