Innodb存儲引擎關(guān)鍵特性包括:
- 插入緩沖 (Insert Buffer)
- 兩次寫 (Double Write)
- 自適應(yīng)哈希索引 (Adaptive Hash Index)
- 異步IO (Async IO)
- 刷新領(lǐng)接頁(Flush Neighbor Page)
插入緩沖 Insert Buffer
Innodb引擎開創(chuàng)性地設(shè)計(jì)了Insert Buffer赵刑,對于非聚集索引的插入或更新操作不是一次性地插入到索引頁中浅浮,而是先判斷插入的非聚集索引頁是否在緩沖池中照藻,若在則插入凉唐,不在,則先放到Insert Buffer中(對應(yīng)有磁盤存儲肘习,但是因?yàn)槭琼樞虻谋炼祝瘦^高)蹋宦,然后再通過merge操作合并Insert Buffer和輔助索引頁惯退,以提高對于非聚集索引插入的性能。
Insert Buffer只是針對非聚集索引的插入和更新操作从藤,使用Insert Buffer需要同時滿足兩個條件:
- 索引是輔助索引
- 索引不是唯一索引
對于聚集索引(innodb數(shù)據(jù)頁)和唯一的聚集索引都不能用Insert Buffer催跪,原因:
- 聚集索引(主鍵索引)大多數(shù)是自增的,即有序的夷野,符合“磁盤順序讀寫不差于隨機(jī)存儲設(shè)備”
- 唯一索引需要判斷插入記錄的唯一性懊蒸,同樣有“離散讀”的問題,導(dǎo)致Insert Buffer失去意義
Insert buffer實(shí)現(xiàn)
Insert Buffer的數(shù)據(jù)結(jié)構(gòu)是一棵B+樹悯搔,在MYSQL 4.1之前的版本中每張表都有一棵Insert Buffer B+樹骑丸,在現(xiàn)在的版本中,全局維護(hù)一棵B+樹妒貌。非葉子節(jié)點(diǎn)存放search key:space+marker+offset通危。space表示待插入記錄鎖在表的表空間id,每張表都有一個唯一的space id灌曙,marker是兼容老版本的insert buffer菊碟,offset表示頁所在的偏移量。所以一個非唯一的輔助索引要插入到頁時在刺,如果這個頁不在緩沖池中逆害,那么首先根據(jù)上述規(guī)則構(gòu)造一個search key,然后插入到insert buffer中蚣驼,插入的記錄為search key(space+marker+offset)+metadata+secondary index record魄幕,metadata記錄了一些插入的其它元數(shù)據(jù)信息。
Insert buffer的合并
insert buffer什么時候合并到真正的索引樹中去呢颖杏?概括的來說纯陨,Merge Insert Buffer的操作可能發(fā)生在以下幾種情況:
- 輔助索引頁被讀取到緩沖池時;(查詢會要求緩沖索引頁)
- Insert Buffer Bitmap頁追蹤到該索引insert buffer已無可用空間時
- Master Thread定時合并(每次Master Thread并非合并所有的頁输玷,會根據(jù)算法選擇一定比例的頁合并)
兩次寫
當(dāng)數(shù)據(jù)庫發(fā)生宕機(jī)后队丝,內(nèi)存的數(shù)據(jù)還沒有寫到磁盤中,這時候該怎么恢復(fù)數(shù)據(jù)呢欲鹏?我們當(dāng)然會想到redo log机久,但是redo log記錄的是對頁的物理操作,如果一個頁大小為16KB赔嚎,只寫入了前4KB膘盖,之后發(fā)生宕機(jī)胧弛,依照redo log來恢復(fù)數(shù)據(jù)是沒有意義的,因?yàn)檫@個頁本身發(fā)生了部分寫導(dǎo)致的損壞侠畔。為了避免部分寫導(dǎo)致的數(shù)據(jù)丟失的情況结缚,innodb采取了double write技術(shù),在對緩存池的臟頁進(jìn)行刷新的時候软棺,并不直接寫入磁盤红竭,而是先將臟頁復(fù)制到doublewrite buffer中,之后將doublewrite buffer分兩次喘落,順序的寫入到物理磁盤上茵宪,然后調(diào)用fsync函數(shù),同步磁盤瘦棋。(當(dāng)fsync刷新臟頁發(fā)生部分寫時稀火,通過doublewrite和redolog恢復(fù)。如果doublewrite寫入磁盤本身發(fā)生問題赌朋,就直接通過redolog恢復(fù)凰狞,沒有部分寫的問題)。
doublewrite大小為2MB沛慢,磁盤上在共享表空間的連續(xù)的128個頁赡若,即2個區(qū),因此也是連續(xù)的颠焦,順序讀寫的開銷也不是很大斩熊。參數(shù)skip_innodb_doublewrite可以禁止用doublewrite功能,在slave server關(guān)閉doublewrite可以提高性能伐庭,不過對于需要提供高可用性的主服務(wù)器(master server)粉渠,應(yīng)該開啟doublewrite功能。
有些文件系統(tǒng)本身就提供了部分寫失效的防范機(jī)制圾另,如ZFS文件系統(tǒng)霸株,這種情況用戶就不用啟用double write了。
自適應(yīng)哈希索引
在生產(chǎn)環(huán)境中集乔,B+樹的高度一般為3-4層去件,故需要3-4次查詢。一般情況下哈希的查找時間復(fù)雜度為O(1)扰路。innodb引擎會監(jiān)控表上各索引頁的查詢尤溜,如果觀察到建立哈希索引可以帶來速度提升,則建立哈希索引汗唱,稱之為自適應(yīng)哈希索引(Adaptive Hash Index, AHI)宫莱。AHI通過緩沖池的B+樹頁構(gòu)造,因此建立速度很快哩罪,而且也不需要對整張表構(gòu)建哈希索引授霸,只需要對熱點(diǎn)頁構(gòu)建巡验。
AHI構(gòu)建的條件:
- 連續(xù)訪問模式一樣,例如聯(lián)合索引(a碘耳,b)WHERE a=xxx 和 WHERE a=xxx b=xxx不一樣
- 以該模式訪問了100次
- 頁通過該模式訪問了N次显设,N=頁中記錄*1/16
哈希相比于B+樹不是sorted,所以對于范圍查詢是不能使用哈希索引的辛辨。根據(jù)innodb存儲引擎官方文檔顯示捕捂,啟用AHI后,讀取和寫入速度可以提高2倍斗搞,輔助索引的連接索引可以提高5倍绞蹦。AHI的設(shè)計(jì)思想是數(shù)據(jù)庫的自優(yōu)化(self-tuning),即不需要DBA的介入對數(shù)據(jù)庫的優(yōu)化榜旦。
異步IO
相比于Sync IO,用戶可以在發(fā)出一個IO請求后立即再發(fā)出另一個IO請求景殷,當(dāng)全部IO請求發(fā)送完畢后溅呢,等待IO操作的完成。AIO不僅讓IO操作可以并行的進(jìn)行猿挚,充分的利用計(jì)算機(jī)的資源咐旧,AIO的另一個優(yōu)勢是可以進(jìn)行IO Merge操作,將多個IO合并成一個IO绩蜻,提高IOPS的性能铣墨。
在innodb 1.1.x之前,AIO通過存儲引擎中代碼來模擬實(shí)現(xiàn)办绝,在這個版本之后伊约,innodb提供了內(nèi)核級別AIO的支持。并不是所有操作系統(tǒng)提供Native AIO的支持孕蝉,不支持的話依舊只能使用模擬的方式屡律。官方的測試顯示,啟用Native AIO比模擬方式速度可以提高75%降淮。(mac osx系統(tǒng)未提供Native AIO)
刷新領(lǐng)接頁
當(dāng)刷新一個臟頁時超埋,innodb存儲引擎會檢測該頁所在區(qū)(extent)的所有頁,如果是臟頁則一起刷新佳鳖,這樣可以通過AIO的IO合并帶來性能提升(順序讀寫)霍殴,故該機(jī)制在傳統(tǒng)機(jī)械硬盤下有著顯著的優(yōu)勢。但是刷新領(lǐng)接頁會帶來兩個問題:
- 是不是把不怎么臟的頁刷新了系吩,該頁會很快又變成了臟頁来庭?
- 固態(tài)硬盤有著較高的IOPS,是否還需要這個特性淑玫?
現(xiàn)在計(jì)算機(jī)的發(fā)展中巾腕,CPU面睛,GPU以及網(wǎng)絡(luò)的發(fā)展要遠(yuǎn)遠(yuǎn)迅速于存儲設(shè)備的發(fā)展,機(jī)械硬盤成為了計(jì)算機(jī)性能的一個瓶頸尊搬,但是將來隨著廉價的Flash Disk的發(fā)展叁鉴,也許固態(tài)硬盤會越來越多的使用。對于固態(tài)硬盤佛寿,建議將參數(shù)innodb_flush_neighbors設(shè)置成0幌墓,關(guān)閉刷新領(lǐng)接頁的特性。