1. 程式人生 > >深入瞭解MySQL儲存引擎-------InnoDB

深入瞭解MySQL儲存引擎-------InnoDB

如果想看自己的資料庫預設使用的那個儲存引擎,可以通過使用命令SHOW VARIABLES LIKE 'storage_engine';

一、InnoDB儲存引擎

1.InnoDB是事務型資料庫的首選引擎,支援事務安全表(ACID)

事務的ACID屬性:即原子性、一致性、隔離性、永續性

                            a.原子性:原子性也就是說這組語句要麼全部執行,要麼全部不執行,如果事務執行到一半出現錯誤,資料庫就要回滾到事務開始執行的地方。

實現:主要是基於MySQ日誌系統的redo和undo機制。事務是一組SQL語句,裡面有選擇,查詢、刪除等功能。每條語句執行會有一個節點。例如,刪除語句執行後,在事務中有個記錄儲存下來,這個記錄中儲存了我們什麼時候做了什麼事。如果出錯了,就會回滾到原來的位置,redo裡面已經儲存了我做過什麼事了,然後逆向執行一遍就可以了。


                                b.一致性:事務開始前和結束後,資料庫的完整性約束沒有被破壞。(eg:比如A向B轉賬,不可能A扣了錢,B卻沒有收到)

                                c.隔離性:同一時間,只允許一個事務請求同一資料,不同的事務之間彼此沒有任何干擾;

如果不考慮隔離性則會出現幾個問題:

 i、髒讀:是指在一個事務處理過程裡讀取了另一個未提交的事務中的資料(當一個事務正在多次修改某個資料,而在這個事務中這多次的修改都還未提交,這時一個併發的事務來訪問該資料,就會造成兩個事務得到的資料不一致);(讀取了另一個事務未提交的髒資料)


  ii、不可重複讀:在對於資料庫中的某個資料,一個事務範圍內多次查詢卻返回了不同的資料值,這是由於在查詢間隔,被另一個事務修改並提交了;(讀取了前一個事務提交的資料,查詢的都是同一個資料項)

   iii、虛讀(幻讀):是事務非獨立執行時發生的一種現象(eg:事務T1對一個表中所有的行的某個資料項做了從“1”修改為“2”的操作,這時事務T2又對這個表中插入了一行資料項,而這個資料項的數值還是為“1”並且提交給資料庫。而操作事務T1的使用者如果再檢視剛剛修改的資料,會發現還有一行沒有修改,其實這行是從事務T2中新增的,就好像產生幻覺一樣);(讀取了前一個事務提交的資料,針對一批資料整體)

                                d.永續性:事務完成後,事務對資料庫的所有更新將被儲存到資料庫,不能回滾

2.InnoDB是mySQL預設的儲存引擎,預設的隔離級別是RR,並且在RR的隔離級別下更近一步,通過多版本併發控制(MVCC)解決不可重複讀問題,加上間隙鎖(也就是併發控制)解決幻讀問題。因此InnoDB的RR隔離級別其實實現了序列化級別的效果,而保留了比較好的併發效能。

MySQL資料庫為我們提供的四種隔離級別:

a、Serializable(序列化):可避免髒讀、不可重複讀、幻讀的發生;

b、Repeatable read(可重複讀):可避免髒讀、不可重複讀的發生;

c、Read committed(讀已提交):可避免髒讀的發生;

d、Read uncommitted(讀未提交):最低級別,任何情況都無法保證;

從a----d隔離級別由高到低,級別越高,執行效率越低

3.InnoDB支援行級鎖。行級鎖可以最大程度的支援併發,行級鎖是由儲存引擎層實現的。

:鎖的主要作用是管理共享資源的併發訪問,用於實現事務的隔離性

        型別:共享鎖(讀鎖)、獨佔鎖(寫鎖)

 MySQL鎖的力度:表級鎖(開銷小、併發性低),通常在伺服器層實現

                                    行級鎖(開銷大、併發性高),只會在儲存引擎層面進行實現

4、InnoDB是為處理巨大資料量的最大效能設計。它的CPU效率可能是任何基於磁碟的關係型資料庫引擎所不能匹敵的

5、InnoDB儲存引擎完全與MySQL伺服器整合,InnoDB儲存引擎為在主記憶體中快取資料和索引而維持它自己的緩衝池。InnoDB將它的表和索引在一個邏輯表空間中,表空間可以包含數個檔案(或原始磁碟檔案);

6、InnoDB支援外來鍵完整性約束,儲存表中的資料時,每張表的儲存都按照主鍵順序存放,如果沒有顯示在表定義時指定主鍵。InnoDB會為每一行生成一個6位元組的ROWID,並以此作為主鍵

7、InnoDB被用在眾多需要高效能的大型資料庫站點上

8、InnoDB中不儲存表的行數(eg:select count(*)from table時,InnoDB需要掃描一遍整個表來計算有多少行);清空整個表時,InnoDB是一行一行的刪除,效率非常慢;

InnoDB不建立目錄,使用InnoDB時,MySQL將在MySQL資料目錄下建立一個名為ibdata1的10MB大小的自動擴充套件資料檔案,以及兩個名為ib_logfile0和ib_logfile1的5MB大小的日誌檔案

二、InnoDB引擎的底層實現

InnoDB的儲存檔案有兩個,字尾名分別是 .frm和 .idb;其中 .frm是表的定義檔案, .idb是表的資料檔案。

1、InnoDB引擎採用B+Tree結構來作為索引結構

B-Tree(平衡多路查詢樹):為磁碟等外儲存裝置設計的一種平衡查詢樹

系統從磁碟讀取資料到記憶體時是以磁碟塊位基本單位的,位於同一磁碟塊中的資料會被一次性讀取出來,而不是按需讀取。

InnoDB儲存引擎使用頁作為資料讀取單位,頁是其磁碟管理的最小單位,預設page大小是16k.

系統的一個磁碟塊的儲存空間往往沒有那麼大,因此InnoDB每次申請磁碟空間時都會是若干地址連續磁碟塊來達到頁的大小16KB。

InnoDB在把磁碟資料讀入到磁碟時會以頁為基本單位,在查詢資料時,如果一個頁中的每條資料都能助於定位資料記錄的位置,這將會減少磁碟I/O的次數,提高查詢效率。

B-Tree結構的資料可以讓系統高效的找到資料所在的磁碟塊

B-Tree中的每個節點根據實際情況可以包含大量的關鍵字資訊和分支,例:


每個節點佔用一個盤塊的磁碟空間,一個節點上有兩個升序排序的關鍵字和三個指向子樹根節點的指標,指標儲存的是子節點所在磁碟塊的地址。

以根節點為例,關鍵字為17和35,P1指標指向的子樹的資料範圍小於17,P2指標指向的子樹的資料範圍為17----35,P3指標指向的子樹的資料範圍大於35;

模擬查詢關鍵字29的過程:

a.根據根節點找到磁碟塊1,讀入記憶體。【磁碟I/O操作第一次】

b.比較關鍵字29在區間(17,35),找到磁碟塊1的指標P2;

c.根據P2指標找到磁碟塊3,讀入記憶體。【磁碟I/O操作第二次】

d.比較關鍵字29在區間(26,30),找到磁碟塊3的指標P2;

e.根據P2指標找到磁碟塊8,讀入記憶體。【磁碟I/O操作第三次】

f.在磁碟塊8中的關鍵字列表中找到關鍵字29.

MySQL的InnoDB儲存引擎在設計時是將根節點常駐記憶體的,因此力求達到樹的深度不超過3,也就是I/O不需要超過三次;

分析上面的結果,發現需要三次磁碟I/O操作,和三次記憶體查詢操作。由於記憶體中的關鍵字是一個有序表結構,可以利用二分法查詢提高效率;而三次磁碟I/O操作時影響整個B-Tree查詢效率的決定因素。

B+Tree

B+Tree是在B-Tree基礎上的一種優化,使其更適合實現外儲存索引結構,B-Tree中每個節點中有key,也有data,而每一頁的儲存空間是有限的,如果data資料較大時將會導致每個節點(即一個頁)能儲存的key的數量很小。當儲存的資料量很大時同樣會導致B-Tree的深度較大,增大查詢時的磁碟I/O次數,進而影響查詢效率。

在B+Tree中所有資料記錄節點都是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點上只儲存key值資訊,這樣可以大大加大每個節點儲存的key值數量,降低B+Tree的高度;

B+Tree在B-Tree的基礎上有兩點變化:(1)資料是存在葉子節點中的

                                                         (2)資料節點之間是有指標指向的

由於B+Tree的非葉子節點只儲存鍵值資訊,假設每個磁碟塊能儲存4個鍵值及指標資訊,則變成B+Tree後其結構如下圖所示:


通常在B+Tree上有兩個頭指標,一個指向根節點,另一個指向關鍵字最小的葉子節點,而且所有葉子節點(即資料節點)之間是一種鏈式環結構。

因此可以對B+Tree進行兩種查詢運算,一種是對於主鍵的範圍查詢和分頁查詢,另一種是從根節點開始,進行隨機查詢。

InnoDB中的B+Tree

InnoDB是以ID為索引的資料儲存

採用InnoDB引擎的資料儲存檔案有兩個,一個定義檔案,一個是資料檔案。

InnoDB通過B+Tree結構對ID建索引,然後在葉子節點中儲存記錄


若建立索引的欄位不是主鍵ID,則對該欄位建索引,然後在葉子節點中儲存的是該記錄的主鍵,然後通過主鍵索引找到對應記錄