數據庫存儲引擎是數據庫底層軟件組織,數據庫管理系統(DBMS)使用數據引擎進行建立、查詢、更新和刪除數據。不一樣的存儲引擎提供不一樣的存儲機制、索引技巧、鎖定水平等功能,使用不一樣的存儲引擎,還能夠 得到特定的功能。如今許多不一樣的數據庫管理系統都支持多種不一樣的數據引擎。MySQL的核心就是存儲引擎。mysql
不一樣的存儲引擎都有各自的特色,以適應不一樣的需求,以下表所示:算法
功 能sql |
MYISAM數據庫 |
Memory緩存 |
InnoDB安全 |
Archive服務器 |
存儲限制數據結構 |
256TB併發 |
RAM |
64TB |
None |
支持事物 |
No |
No |
Yes |
No |
支持全文索引 |
Yes |
No |
No |
No |
支持數索引 |
Yes |
Yes |
Yes |
No |
支持哈希索引 |
No |
Yes |
No |
No |
支持數據緩存 |
No |
N/A |
Yes |
No |
支持外鍵 |
No |
No |
Yes |
No |
若是要提供提交、回滾、崩潰恢復能力的事物安全(ACID兼容)能力,並要求實現併發控制,InnoDB是一個好的選擇
若是數據表主要用來插入和查詢記錄,則MyISAM引擎能提供較高的處理效率
若是隻是臨時存放數據,數據量不大,而且不須要較高的數據安全性,能夠選擇將數據保存在內存中的Memory引擎,MySQL中使用該引擎做爲臨時表,存放查詢的中間結果
若是隻有INSERT和SELECT操做,能夠選擇Archive,Archive支持高併發的插入操做,可是自己不是事務安全的。Archive很是適合存儲歸檔數據,如記錄日誌信息可使用Archive
使用哪種引擎須要靈活選擇,一個數據庫中多個表可使用不一樣引擎以知足各類性能和實際需求,使用合適的存儲引擎,將會提升整個數據庫的性能
mysql給開發者提供了查詢存儲引擎的功能,我這裏使用的是MySQL5.1,可使用:
命令來查看MySQL使用的引擎,命令的輸出爲(我用的Navicat Premium):
看到MySQL給用戶提供了這麼多存儲引擎,包括處理事務安全表的引擎和出來了非事物安全表的引擎。
SHOW VARIABLES LIKE 'storage_engine';
在MySQL中,不須要在整個服務器中使用同一種存儲引擎,針對具體的要求,能夠對每個表使用不一樣的存儲引擎。Support列的值表示某種引擎是否能使用:YES表示可使用、NO表示不能使用、DEFAULT表示該引擎爲當前默認的存儲引擎 。下面來看一下其中幾種經常使用的引擎。
InnoDB是事務型數據庫的首選引擎,支持事務安全表(ACID),支持行鎖定和外鍵,上圖也看到
了,InnoDB是默認的MySQL引擎。InnoDB主要特性有:
一、InnoDB給MySQL提供了具備提交、回滾和崩潰恢復能力的事物安全(ACID兼容)存儲引擎。InnoDB鎖定在行級而且也在SELECT語句中提供一個相似Oracle的非鎖定讀。這些功能增長了多用戶部署和性能。在SQL查詢中,能夠自由地將InnoDB類型的表和其餘MySQL的表類型混合起來,甚至在同一個查詢中也能夠混合
二、InnoDB是爲處理巨大數據量的最大性能設計。它的CPU效率多是任何其餘基於磁盤的關係型數據庫引擎鎖不能匹敵的
三、InnoDB存儲引擎徹底與MySQL服務器整合,InnoDB存儲引擎爲在主內存中緩存數據和索引而維持它本身的緩衝池。InnoDB將它的表和索引在一個邏輯表空間中,表空間能夠包含數個文件(或原始磁盤文件)。這與MyISAM表不一樣,好比在MyISAM表中每一個表被存放在分離的文件中。InnoDB表能夠是任何尺寸,即便在文件尺寸被限制爲2GB的操做系統上
四、InnoDB支持外鍵完整性約束,存儲表中的數據時,每張表的存儲都按主鍵順序存放,若是沒有顯示在表定義時指定主鍵,InnoDB會爲每一行生成一個6字節的ROWID,並以此做爲主鍵
InnoDB不建立目錄,使用InnoDB時,MySQL將在MySQL數據目錄下建立一個名爲ibdata1的10MB大小的自動擴展數據文件,以及兩個名爲ib_logfile0和ib_logfile1的5MB大小的日誌文件
MyISAM基於ISAM存儲引擎,並對其進行擴展。它是在Web、數據倉儲和其餘應用環境下最常使用的存儲引擎之一。MyISAM擁有較高的插入、查詢速度,但不支持事物。MyISAM主要特性有:
一、大文件(達到63位文件長度)在支持大文件的文件系統和操做系統上被支持
二、當把刪除和更新及插入操做混合使用的時候,動態尺寸的行產生更少碎片。這要經過合併相鄰被刪除的塊,以及若下一個塊被刪除,就擴展到下一塊自動完成
三、每一個MyISAM表最大索引數是64,這能夠經過從新編譯來改變。每一個索引最大的列數是16
四、最大的鍵長度是1000字節,這也能夠經過編譯來改變,對於鍵長度超過250字節的狀況,一個超過1024字節的鍵將被用上
六、NULL被容許在索引的列中,這個值佔每一個鍵的0~1個字節
八、每一個MyISAM類型的表都有一個AUTO_INCREMENT的內部列,當INSERT和UPDATE操做的時候該列被更新,同時AUTO_INCREMENT列將被刷新。因此說,MyISAM類型表的AUTO_INCREMENT列更新比InnoDB類型的AUTO_INCREMENT更快
使用MyISAM引擎建立數據庫,將產生3個文件。文件的名字以表名字開始,擴展名之處文件類型:frm文件存儲表定義、數據文件的擴展名爲.MYD(MYData)、索引文件的擴展名時.MYI(MYIndex)
MEMORY存儲引擎將表中的數據存儲到內存中,未查詢和引用其餘表數據提供快速訪問。MEMORY主要特性有:
一、MEMORY表的每一個表能夠有多達32個索引,每一個索引16列,以及500字節的最大鍵長度
六、MEMORY支持AUTO_INCREMENT列和對可包含NULL值的列的索引
七、MEMORY表在所由客戶端之間共享(就像其餘任何非TEMPORARY表)
八、MEMORY表內存被存儲在內存中,內存是MEMORY表和服務器在查詢處理時的空閒中,建立的內部表共享
九、當再也不須要MEMORY表的內容時,要釋放被MEMORY表使用的內存,應該執行DELETE FROM或TRUNCATE TABLE,或者刪除整個表(使用DROP TABLE)
一、Hash存儲引擎
表明數據庫:redis、memcache等
一般也常見於其餘存儲引擎的查找速度優化上。 Hash 索引結構的特殊性,其檢索效率很是高,索引的檢索能夠一次定位,不像B-Tree 索引須要從根節點到枝節點,最後才能訪問到頁節點這樣屢次的IO訪問,因此 Hash 索引的查詢效率要遠高於 B-Tree 索引。雖然 Hash 索引效率高,可是 Hash 索引自己因爲其特殊性也帶來了不少限制和弊端。
這裏列舉缺點:
(1)Hash 索引僅僅能知足"=","IN"和"<=>"查詢,不能使用範圍查詢。
(2)Hash 索引沒法被用來避免數據的排序操做。
(3)Hash 索引不能利用部分索引鍵查詢。
(4)Hash 索引在任什麼時候候都不能避免表掃描。
Hash碰撞,就是鏈式掃描:
因爲不一樣索引鍵存在相同 Hash 值,因此即便取知足某個 Hash 鍵值的數據的記錄條數,也沒法從 Hash索引中直接完成查詢,仍是要經過訪問表中的實際數據進行相應的比較,並獲得相應的結果。
(5)Hash 索引遇到大量Hash值相等的狀況後性能並不必定就會比B-Tree索引高。
二、B樹存儲引擎
表明數據庫:MongoDB、mysql(基本上關係型數據庫)等
還有一種算是B樹存儲引擎:COLA樹(CacheObliviousBTree)
表明數據庫:tokudb
爲了如何讓B樹更有效的執行,他們提出了一個緩存忘卻CacheOblivious算法,該算法在不須要明確知道存儲器層次中數據傳輸規模的狀況下,也能夠高效的工做。更多請參見:https://en.wikipedia.org/wiki/Cache-oblivious_algorithm。
說個你們熟悉的名稱TokuMX : 目前很是流行的NoSQL數據庫MongoDB的底層替換成與TokuDB一樣的存儲引擎[ ToKuMx],達到了很是好的效 果
三、LSM樹(Log-Structured Merge Tree)存儲引擎
表明數據庫:nessDB、leveldb、hbase等
核心思想的核心就是放棄部分讀能力,換取寫入的最大化能力。LSM Tree ,這個概念就是結構化合並樹的意思,它的核心思路其實很是簡單,就是假定內存足夠大,所以不須要每次有數據更新就必須將數據寫入到磁盤中,而能夠先將最新的數據駐留在磁盤中,等到積累到最後多以後,再使用歸併排序的方式將內存內的數據合併追加到磁盤隊尾(由於全部待排序的樹都是有序的,能夠經過合併排序的方式快速合併到一塊兒)。
日誌結構的合併樹(LSM-tree)是一種基於硬盤的數據結構,與B-tree相比,能顯著地減小硬盤磁盤臂的開銷,並能在較長的時間提供對文件的高速插入(刪除)。然而LSM-tree在某些狀況下,特別是在查詢須要快速響應時性能不佳。一般LSM-tree適用於索引插入比檢索更頻繁的應用系統。Bigtable在提供Tablet服務時,使用GFS來存儲日誌和SSTable,而GFS的設計初衷就是但願經過添加新數據的方式而不是經過重寫舊數據的方式來修改文件。而LSM-tree經過滾動合併和多頁塊的方法推遲和批量進行索引更新,充分利用內存來存儲近期或經常使用數據以下降查找代價,利用硬盤來存儲不經常使用數據以減小存儲代價。
磁盤的技術特性:對磁盤來講,可以最大化的發揮磁盤技術特性的使用方式是:一次性的讀取或寫入固定大小的一塊數據,並儘量的減小隨機尋道這個操做的次數。
LSM和Btree差別就要在讀性能和寫性能進行舍和求。在犧牲的同事,尋找其餘方案來彌補。
一、LSM具備批量特性,存儲延遲。當寫讀比例很大的時候(寫比讀多),LSM樹相比於B樹有更好的性能。由於隨着insert操做,爲了維護B樹結構,節點分裂。讀磁盤的隨機讀寫機率會變大,性能會逐漸減弱。 屢次單頁隨機寫,變成一次多頁隨機寫,複用了磁盤尋道時間,極大提高效率。
二、B樹的寫入過程:對B樹的寫入過程是一次原位寫入的過程,主要分爲兩個部分,首先是查找到對應的塊的位置,而後將新數據寫入到剛纔查找到的數據塊中,而後再查找到塊所對應的磁盤物理位置,將數據寫入去。固然,在內存比較充足的時候,由於B樹的一部分能夠被緩存在內存中,因此查找塊的過程有必定機率能夠在內存內完成,不過爲了表述清晰,咱們就假定內存很小,只夠存一個B樹塊大小的數據吧。能夠看到,在上面的模式中,須要兩次隨機尋道(一次查找,一次原位寫),纔可以完成一次數據的寫入,代價仍是很高的。
三、LSM Tree放棄磁盤讀性能來換取寫的順序性,彷佛會認爲讀應該是大部分系統最應該保證的特性,因此用讀換寫彷佛不是個好買賣。但別急,聽我分析一下。
a、內存的速度遠超磁盤,1000倍以上。而讀取的性能提高,主要仍是依靠內存命中率而非磁盤讀的次數
b、寫入不佔用磁盤的io,讀取就能獲取更長時間的磁盤io使用權,從而也能夠提高讀取效率。例如LevelDb的SSTable雖然下降了了讀的性能,但若是數據的讀取命中率有保障的前提下,由於讀取可以得到更多的磁盤io機會,所以讀取性能基本沒有下降,甚至還會有提高。而寫入的性能則會得到較大幅度的提高,基本上是5~10倍左右。
下面說說詳細例子:
LSM Tree弄了不少個小的有序結構,好比每m個數據,在內存裏排序一次,下面100個數據,再排序一次……這樣依次作下去,我就能夠得到N/m個有序的小的有序結構。
在查詢的時候,由於不知道這個數據究竟是在哪裏,因此就從最新的一個小的有序結構裏作二分查找,找獲得就返回,找不到就繼續找下一個小有序結構,一直到找到爲止。
很容易能夠看出,這樣的模式,讀取的時間複雜度是(N/m)*log2N 。讀取效率是會降低的。
這就是最原本意義上的LSM tree的思路。那麼這樣作,性能仍是比較慢的,因而須要再作些事情來提高,怎麼作纔好呢?
LSM Tree優化方式:
a、Bloom filter: 就是個帶隨即機率的bitmap,能夠快速的告訴你,某一個小的有序結構裏有沒有指定的那個數據的。因而就能夠不用二分查找,而只需簡單的計算幾回就能知道數據是否在某個小集合裏啦。效率獲得了提高,但付出的是空間代價。
b、compact:小樹合併爲大樹:由於小樹他性能有問題,因此要有個進程不斷地將小樹合併到大樹上,這樣大部分的老數據查詢也能夠直接使用log2N的方式找到,不須要再進行(N/m)*log2n的查詢了