1、MySQL邏輯架構
? ? ? ? 最上層的服務并不是 MySQL所獨有的,大多數基于網絡的客戶端/服務器的工具或者服務都有類似的架構。比如連接處理、授權認證、安全等等。
????????第二層架構是 MySQL 比較有意思的部分。大多數 MySQL 的核心服務功能都在這一層包括查詢解析、分析、優化、緩存以及所有的內置函數(例如,日期、時間、數學和加密函數),所有跨存儲引擎的功能都在這一層實現:存儲過程、觸發器、視圖等。
????????第三層包含了存儲引擎。存儲引擎負責 MySOL中數據的存儲和提取。和 GNU/Linux 下的各種文件系統一樣,每個存儲引擎都有它的優勢和劣勢。服務器通過 API 與存儲引擎進行通信。這些接口屏蔽了不同存儲引擎之間的差異,使得這些差異對上層的查詢過程透明。存儲引擎 API包含幾十個底層函數,用于執行諸如“開始一個事務”或者“根據主鍵提取一行記錄”等操作。但存儲引擎不會去解析 SQL,不同存儲引擎之間也不會相互通信,而只是簡單地響應上層服務器的請求。
1.1、連接管理與安全性
????????每個客戶端連接都會在服務器進程中擁有一個線程,這個連接的査詢只會在這個單獨的線程中執行,該線程只能輪流在某個 CPU 核心或者 CPU 中運行。服務器會負責緩存線程,因此不需要為每一個新建的連接創建或者銷毀線程。當客戶端(應用)連接到 MySQL服務器時,服務器需要對其進行認證。認證基于用戶名、原始主機信息和密碼。如果使用了安全套接字(SSL)的方式連接,還可以使用X.509證書認證。一旦客戶端連接成功,服務器會繼續驗證該客戶端是否具有執行某個特定查詢的權限(例如,是否允許客戶端對世界數據庫的國家)表執行SELECT語句)
1.2、優化與執行
????????MySQL會解析查詢,并創建內部數據結構(解析樹),然后對其進行各種優化包括重寫查詢、決定表的讀取順序,以及選擇合適的索引等。用戶可以通過特殊的關鍵字提示(提示)優化器,影響它的決策過程。也可以請求優化器解釋(explain)優化過程的各個因素,使用戶可以知道服務器是如何進行優化決策的,并提供一個參考基準,便于用戶重構查詢和模式、修改相關配置使應用盡可能高效運行。
????????優化器并不關心表使用的是什么存儲引擎,但存儲引擎對于優化查詢是有影響的。優化器會請求存儲引擎提供容量或某個具體操作的開銷信息,以及表數據的統計信息等。例如,某些存儲引擎的某種索引,可能對一些特定的查詢有優化。對于SELECT語句,在解析查詢之前,服務器會先檢查查詢緩存,如果能夠在其.中找到對應的查詢,服務器就不必再執行查詢解析、優化和執行的整個過程,而是直接返回查詢緩存中的結果集。
2、并發控制
????????無論何時,只要有多個查詢需要在同一時刻修改數據,都會產生并發控制的問題。本文的目的是討論 MySQL在兩個層面的并發控制:服務器層與存儲引擎層。并發控制是一個內容龐大的話題,有大量的理論文獻對其進行過詳細的論述。本文只簡要地討論MySQL如何控制并發讀寫。
????????以 Unix 系統的 email box為例,典型的 mbox 文件格式是非常簡單的。一個 mbox 郵箱中的所有郵件都串行在一起,彼此首尾相連。這種格式對于讀取和分析郵件信息非常友好,同時投遞郵件也很容易,只要在文件末尾附加新的郵件內容即可。
????????但如果兩個進程在同一時刻對同一個郵箱投遞郵件,會發生什么情況?顯然,郵箱的數據會被破壞,兩封郵件的內容會交叉地附加在郵箱文件的末尾。設計良好的郵箱投遞系統會通過鎖(1ock)來防止數據損壞。如果客戶試圖投遞郵件,而郵箱已經被其他客戶鎖住那就必須等待,直到鎖釋放才能進行投遞。
????????這種鎖的方案在實際應用環境中雖然工作良好,但并不支持并發處理。因為在任意一個時刻,只有一個進程可以修改郵箱的數據,這在大容量的郵箱系統中是個問題。
2.1、讀寫鎖
????????從郵箱中讀取數據沒有這樣的麻煩,即使同一時刻多個用戶并發讀取也不會有什么問題因為讀取不會修改數據,所以不會出錯。但如果某個客戶正在讀取郵箱,同時另外一個用戶試圖刪除編號為 25 的郵件,會產生什么結果?結論是不確定,讀的客戶可能會報錯退出,也可能讀取到不一致的郵箱數據。所以,為安全起見,即使是讀取郵箱也需要特別注意。
????????如果把上述的郵箱當成數據庫中的一張表,把郵件當成表中的一行記錄,就很容易看出,同樣的問題依然存在。從很多方面來說,郵箱就是一張簡單的數據庫表。修改數據庫表中的記錄,和刪除或者修改郵箱中的郵件信息,十分類似。
????????解決這類經典問題的方法就是并發控制,其實非常簡單。在處理并發讀或者寫時,可以通過實現一個由兩種類型的鎖組成的鎖系統來解決問題。這兩種類型的鎖通常被稱為共享鎖(shared 1ock)和排他鎖(exclusive lock),也叫讀鎖(read lock)和寫鎖(writelock)。
????????這里先不討論鎖的具體實現,描述一下鎖的概念如下: 讀鎖是共享的,或者說是相互不阻塞的。多個客戶在同一時刻可以同時讀取同一個資源,而互不干擾。寫鎖則是排他的也就是說一個寫鎖會阻塞其他的寫鎖和讀鎖,這是出于安全策略的考慮,只有這樣,才能確保在給定的時間里,只有一個用戶能執行寫入,并防止其他用戶讀取正在寫入的同一資源。
????????在實際的數據庫系統中,每時每刻都在發生鎖定,當某個用戶在修改某一部分數據時MySQL 會通過鎖定防止其他用戶讀取同一數據。大多數時候,MySQL鎖的內部管理都是透明的。
2.2、鎖粒度
????????一種提高共享資源并發性的方式就是讓鎖定對象更有選擇性。盡量只鎖定需要修改的部分數據,而不是所有的資源。更理想的方式是,只對會修改的數據片進行精確的鎖定任何時候,在給定的資源上,鎖定的數據量越少,則系統的并發程度越高,只要相互之間不發生沖突即可。
????????問題是加鎖也需要消耗資源。鎖的各種操作,包括獲得鎖、檢查鎖是否已經解除、釋放鎖等,都會增加系統的開銷。如果系統花費大量的時間來管理鎖,而不是存取數據,那么系統的性能可能會因此受到影響。
????????所謂的鎖策略,就是在鎖的開銷和數據的安全性之間尋求平衡,這種平衡當然也會影響到性能。大多數商業數據庫系統沒有提供更多的選擇,一般都是在表上施加行級鎖(row-level 1ock),并以各種復雜的方式來實現,以便在鎖比較多的情況下盡可能地提供更好的性能。
????????而MySOL則提供了多種選擇。每種MySQL存儲引擎都可以實現自己的鎖策略和鎖粒度。在存儲引擎的設計中,鎖管理是個非常重要的決定。將鎖粒度固定在某個級別,可以為某些特定的應用場景提供更好的性能,但同時卻會失去對另外一些應用場景的良好支持。好在 MySQL支持多個存儲引擎的架構,所以不需要單一的通用解決方案。下面將介紹兩種最重要的鎖策略。
2.2.1、表鎖(table lock)
????????表鎖是 MySQL,中最基本的鎖策略,并且是開銷最小的策略。表鎖非常類似于前文描述的郵箱加鎖機制:它會鎖定整張表。一個用戶在對表進行寫操作(插入、刪除、更新等)前,需要先獲得寫鎖,這會阻塞其他用戶對該表的所有讀寫操作。只有沒有寫鎖時,其他讀取的用戶才能獲得讀鎖,讀鎖之間是不相互阻塞的。
????????在特定的場景中,表鎖也可能有良好的性能。例如,READ LOCAL表鎖支持某些類型的并發寫操作。另外,寫鎖也比讀鎖有更高的優先級,因此一個寫鎖請求可能會被插入到讀鎖隊列的前面(寫鎖可以插入到鎖隊列中讀鎖的前面,反之讀鎖則不能插入到寫鎖的前面)。
????????盡管存儲引擎可以管理自己的鎖,MySQL本身還是會使用各種有效的表鎖來實現不同的目的。例如,服務器會為諸如 ALTER TABLE之類的語句使用表鎖,而忽略存儲引擎的鎖機制。
2.2.2、行級鎖(row lock)
????????行級鎖可以最大程度地支持并發處理(同時也帶來了最大的鎖開銷)。眾所周知,在InnoDB 和 XtraDB,以及其他一些存儲引擎中實現了行級鎖。行級鎖只在存儲引擎層實現,而 MySQL服務器層(如有必要,請回顧前文的邏輯架構圖)沒有實現。服務器層完全不了解存儲引擎中的鎖實現。在本章的后續內容以及全書中,所有的存儲引擎都以自己的方式顯現了鎖機制。
3、事務
????????在理解事務的概念之前,接觸數據庫系統的其他高級特性還言之過早。事務就是一組原子性的 SQL查詢,或者說一個獨立的工作單元。如果數據庫引擎能夠成功地對數據庫應用該組查詢的全部語句,那么就執行該組查詢。如果其中有任何一條語句因為崩潰或其他原因無法執行,那么所有的語句都不會執行。也就是說,事務內的語句,要么全部執行成功,要么全部執行失敗。
? ? ? ? 事務的ACID和事務的隔離級別在此就不贅述。
3.1、事務日志
????????事務日志可以幫助提高事務的效率。使用事務日志,存儲引擎在修改表的數據時只需要修改其內存拷貝,再把該修改行為記錄到持久在硬盤上的事務日志中,而不用每次都將修改的數據本身持久到磁盤。事務日志采用的是追加的方式,因此寫日志的操作是磁盤上一小塊區域內的順序 I/O,而不像隨機I/0 需要在磁盤的多個地方移動磁頭,所以采用事務日志的方式相對來說要快得多。事務日志持久以后,內存中被修改的數據在后臺可以慢慢地刷回到磁盤。目前大多數存儲引警都是這樣實現的,我們通常稱之為預寫式日志(Write-Ahead Logging),修改數據需要寫兩次磁盤。
如果數據的修改已經記錄到事務日志并持久化,但數據本身還沒有寫回磁盤,此時系統崩潰,存儲引擎在重啟時能夠自動恢復這部分修改的數據。具體的恢復方式則視存儲引擎而定。
3.2、MySQL 中的事務
????????MySQL提供了兩種事務型的存儲引擎:InnoDB和NDB Cluster。另外還有一些第三方存儲引擎也支持事務,比較知名的包括 XtraDB 和PBXT。
3.2.1、自動提交(AUTOCOMMIT)
????????MySQL默認采用自動提交(AUTOCOMMIT)模式。也就是說,如果不是顯式地開始一個事務,則每個查詢都被當作一個事務執行提交操作。在當前連接中,可以通過設置AUTO COMMIT 變量來啟用或者禁用自動提交模式。
3.2.2、在事務中混合使用存儲引擎
????????MySQL服務器層不管理事務,事務是由下層的存儲引擎實現的。所以在同一個事務中使用多種存儲引警是不可靠的。
????????如果在事務中混合使用了事務型和非事務型的表(例如InnoDB和 MyISAM 表),在正常提交的情況下不會有什么問題。但如果該事務需要回滾,非事務型的表上的變更就無法撤銷,這會導致數據庫處于不一致的狀態,這種情況很難修復,事務的最終結果將無法確定。所以,為每張表選擇合適的存儲引擎非常重要。
????????在非事務型的表上執行事務相關操作的時候,MySQL通常不會發出提醒,也不會報錯有時候只有回滾的時候才會發出一個警告:“某些非事務型的表上的變更不能被回滾” 但大多數情況下,對非事務型表的操作都不會有提示。
3.2.3、隱式和顯式鎖定
????????InnoDB 采用的是兩階段鎖定協議(two-phase locking protocol)。在事務執行過程中,隨時都可以執行鎖定,鎖只有在執行COMMIT 或者 ROLLBACK的時候才會釋放,并且所有的鎖是在同一時刻被釋放。前面描述的鎖定都是隱式鎖定,InnoDB 會根據隔離級別在需要的時候自動加鎖。
????????另外,InnoDB 也支持通過特定的語句進行顯式鎖定,這些語句不屬于 SQL規范
LOCK IN SHARE MODESELECT
SELECT ... FOR UPDATE
????????MySQL 也支持 LOCK TABLES 和 UNLOCK TABLES 語句,這是在服務器層實現的,和存儲引擎無關。它們有自己的用途,但并不能替代事務處理。如果應用需要用到事務,還是應該選擇事務型存儲引擎。
????????經常可以發現,應用已經將表從MyISAM轉換到InnoDB,但還是顯式地使用LOCK TABLES語句。這不但沒有必要,還會嚴重影響性能,實際上InnoDB 的行級鎖工作得更好。
3.3、多版本并發控制
????????MySQL的大多數事務型存儲引擎實現的都不是簡單的行級鎖。基于提升并發性能的考慮,它們一般都同時實現了多版本并發控制(MVCC)。不僅是 MySQL,包括 Oracle、PostgreSQL等其他數據庫系統也都實現了MVCC,但各自的實現機制不盡相同,因為MVCC 沒有一個統一的實現標準。
????????可以認為 MVCC 是行級鎖的一個變種,但是它在很多情況下避免了加鎖操作,因此開銷更低。雖然實現機制有所不同,但大都實現了非阻塞的讀操作,寫操作也只鎖定必要的行。
????????MVCC的實現,是通過保存數據在某個時間點的快照來實現的。也就是說,不管需要執行多長時間,每個事務看到的數據都是一致的。根據事務開始的時間不同,每個事務對同一張表,同一時刻看到的數據可能是不一樣的。如果之前沒有這方面的概念,這句話聽起來就有點迷惑。熟悉了以后會發現,這句話其實還是很容易理解的。
????????前面說到不同存儲引擎的MVCC 實現是不同的,典型的有樂觀(optimistic)并發控制和悲觀(pessimistic)并發控制。下面我們通過InnoDB 的簡化版行為來說明MVCC 是如何工作的。
????????InnoDB的 MVCC,是通過在每行記錄后面保存兩個隱藏的列來實現的。這兩個列,個保存了行的創建時間,一個保存行的過期時間(或刪除時間)。當然存儲的并不是實際的時間值,而是系統版本號(system version number)。每開始一個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會作為事務的版本號,用來和查詢到的每行記錄的版本號進行比較。下面看一下在 REPEATABLE READ 隔離級別下,MVCC 具體是如何操作的。
SELECT
????????InnoDB 會根據以下兩個條件檢查每行記錄:
????????a. InnoDB 只查找版本早于當前事務版本的數據行(也就是,行的系統版本號小于或等于事務的系統版本號),這樣可以確保事務讀取的行,要么是在事務開始前已經存在的,要么是事務自身插入或者修改過的。
????????b.行的刪除版本要么未定義,要么大于當前事務版本號。這可以確保事務讀取到的行,在事務開始之前未被刪除。
????????只有符合上述兩個條件的記錄,才能返回作為查詢結果
INSERT
InnoDB 為新插入的每一行保存當前系統版本號作為行版本號。
DELETE
InnoDB 為刪除的每一行保存當前系統版本號作為行刪除標識。
UPDATE
InnoDB 為插入一行新記錄,保存當前系統版本號作為行版本號,同時保存當前系統版本號到原來的行作為行刪除標識。
????????保存這兩個額外系統版本號,使大多數讀操作都可以不用加鎖。這樣設計使得讀數據操作很簡單,性能很好,并且也能保證只會讀取到符合標準的行。不足之處是每行記錄都需要額外的存儲空間,需要做更多的行檢查工作,以及一些額外的維護工作。
????????MVCC 只在 REPEATABLE READ和 READ COMMITTED 兩個隔離級別下工作。其他兩個隔離級別都和 MVCC不兼容,因為 READ UNCOMMITTED 總是讀取最新的數據行,而不是符合當前事務版本的數據行。而 SERIALIZABLE 則會對所有讀取的行都加鎖。
4、MySQL 的存儲引擎
4.1、InnoDB 概覽
????????InnoDB 的數據存儲在表空間(tablespace)中,表空間是由InnoDB 管理的一個黑盒子由一系列的數據文件組成。在 MySQL 4.1以后的版本中,InnoDB 可以將每個表的數據和索引存放在單獨的文件中。InnoDB 也可以使用裸設備作為表空間的存儲介質,但現代的文件系統使得裸設備不再是必要的選擇,
????????InnoDB 采用 MVCC 來支持高并發,并且實現了四個標準的隔離級別。其默認級別是REPEATABLE READ(可重復讀),并且通過間隙鎖(next-key locking)策略防止幻讀的出現。間隙鎖使得 InnoDB 不僅僅鎖定查詢涉及的行,還會對索引中的間隙進行鎖定,以防止幻影行的插入。
????????InnoDB 表是基于聚簇索引建立的。InnoDB的索引結構和 MySQL的其他存儲引擎有很大的不同,聚簇索引對主鍵査詢有很高的性能。不過它的二級索引(secondary index,非主鍵索引)中必須包含主鍵列,所以如果主鍵列很大的話,其他的所有索引都會很大。因此,若表上的索引較多的話,主鍵應當盡可能的小。InnoDB 的存儲格式是平臺獨立的,也就是說可以將數據和索引文件從 Intel 平臺復制到 PowerPC 或者 Sun SPARC 平臺。
????????InnoDB 內部做了很多優化,包括從磁盤讀取數據時采用的可預測性預讀,能夠自動在內存中創建 hash 索引以加速讀操作的自適應哈希索引(adaptive hash index),以及能夠加速插入操作的插入緩沖區(insert buffer)等。本書后面將更詳細地討論這些內容。
????????InnoDB 的行為是非常復雜的,不容易理解。如果使用了 InnoDB 引擎,筆者強烈建議讀官方手冊中的“InnoDB 事務模型和鎖”一節。如果應用程序基于 InnoDB 構建,則事先了解一下 InnoDB 的 MVCC 架構帶來的一些微妙和細節之處是非常有必要的。存儲弓警要為所有用戶甚至包括修改數據的用戶維持一致性的視圖,是非常復雜的工作。
????????作為事務型的存儲引擎,InnoDB 通過一些機制和工具支持真正的熱備份,Oracle 提供的 MySQL Enterprise Backup、Percona 提供的開源的 XtraBackup 都可以做到這一點MySQL的其他存儲引擎不支持熱備份,要獲取一致性視圖需要停止對所有表的寫入而在讀寫混合場景中,停止寫入可能也意味著停止讀取。
4.2、MyISAM 存儲引擎
????????在 MySQL 5.1 及之前的版本,MyISAM 是默認的存儲引擎。MyISAM 提供了大量的特性,包括全文索引、壓縮、空間函數(GIS)等,但MyISAM 不支持事務和行級鎖,而且有一個毫無疑問的缺陷就是崩潰后無法安全恢復。正是由于 MyISAM 引擎的緣故,即使MySQL支持事務已經很長時間了,在很多人的概念中 MySQL還是非事務型的數據庫。盡管 MyISAM 引擎不支持事務、不支持崩潰后的安全恢復,但它絕不是一無是處的。對于只讀的數據,或者表比較小、可以忍受修復(repair)操作,則依然可以繼續使用 MyISAM(但請不要默認使用 MyISAM,而是應當默認使用 InnoDB)。
4.2.1、存儲
????????MyISAM 會將表存儲在兩個文件中:數據文件和索引文件,分別以.MYD和.MYI為擴展名。MyISAM 表可以包含動態或者靜態(長度固定)行。MySQL會根據表的定義來決定采用何種行格式。MyISAM 表可以存儲的行記錄數,一般受限于可用的磁盤空間或者操作系統中單個文件的最大尺寸。
????????在MySQL 5.0中,MyISAM 表如果是變長行,則默認配置只能處理 256TB 的數據,因為指向數據記錄的指針長度是6個字節。而在更早的版本中,指針長度默認是4字節,所以只能處理 4GB 的數據。而所有的 MySQL版本都支持8字節的指針。要改變MyISAM 表指針的長度(調高或者調低),可以通過修改表的MAX ROWS和 AVG ROWLENGTH選項的值來實現,兩者相乘就是表可能達到的最大大小。修改這兩個參數會導致重建整個表和表的所有索引,這可能需要很長的時間才能完成。
4.2.2、MyISAM 特性
????????作為MySQL 最早的存儲引擎之一,MyISAM 有一些已經開發出來很多年的特性,可以滿足用戶的實際需求。
加鎖與并發
????????MyISAM 對整張表加鎖,而不是針對行。讀取時會對需要讀到的所有表加共享鎖寫入時則對表加排他鎖。但是在表有讀取查詢的同時,也可以往表中插入新的記錄(這被稱為并發插入,CONCURRENT INSERT)。
修復
????????對于 MyISAM 表,MySQL 可以手工或者自動執行檢査和修復操作,但這里說的修復和事務恢復以及崩潰恢復是不同的概念。執行表的修復可能導致一些數據丟失而且修復操作是非常慢的。可以通過CHECK TABLE mytable檢查表的錯誤,如果有錯誤可以通過執行 REPAIR TABLE mytable進行修復。另外,如果 MySQL 服務器已經關閉,也可以通過 myisamchk 命令行工具進行檢査和修復操作。
索引特性
????????對于 MyISAM 表,即使是 BLOB和 TEXT 等長字段,也可以基于其前 500 個字符創建索引。MyISAM 也支持全文索引,這是一種基于分詞創建的索引,可以支持復雜的查詢。
????????創建 MyISAM 表的時候,如果指定了 DELAY KEY WRITE 選項,在每次修改執行完成時,不會立刻將修改的索引數據寫入磁盤,而是會寫到內存中的鍵緩沖區(in-memorykey buffer),只有在清理鍵緩沖區或者關閉表的時候才會將對應的索引塊寫入到磁盤。這種方式可以極大地提升寫入性能,但是在數據庫或者主機崩潰時會造成索引損壞,需要執行修復操作。延遲更新索引鍵的特性,可以在全局設置,也可以為單個表設置。
MyISAM 壓縮表
????????如果表在創建并導入數據以后,不會再進行修改操作,那么這樣的表或許適合采用MyISAM 壓縮表。
????????可以使用 myisampack 對 MyISAM 表進行壓縮(也叫打包pack)。壓縮表是不能進行修改的(除非先將表解除壓縮,修改數據,然后再次壓縮)。壓縮表可以極大地減少磁盤空間占用,因此也可以減少磁盤 I/0,從而提升查詢性能。壓縮表也支持索引,但索引也是只讀的。
????????以現在的硬件能力,對大多數應用場景,讀取壓縮表數據時的解壓帶來的開銷影響并不大,而減少 I/0 帶來的好處則要大得多。壓縮時表中的記錄是獨立壓縮的,所以讀取單行的時候不需要去解壓整個表(甚至也不解壓行所在的整個頁面)。
MyISAM 性能
????????MyISAM 引擎設計簡單,數據以緊密格式存儲,所以在某些場景下的性能很好MyISAM 有一些服務器級別的性能擴展限制,比如對索引鍵緩沖區(key cache)的Mutex鎖,MariaDB 基于段(segment)的索引鍵緩沖區機制來避免該問題。但 MyISAM最典型的性能問題還是表鎖的問題,如果你發現所有的查詢都長期處于“Locked”狀態那么毫無疑問表鎖就是罪魁禍首
4.3、MySQL 內建的其他存儲引擎
????????MySQL還有一些有特殊用途的存儲引擎。在新版本中,有些可能因為一些原因已經不再支持;另外還有些會繼續支持,但是需要明確地啟用后才能使用。
Archive 引擎
????????Archive 存儲引擎只支持 INSERT和SELECT操作,在 MySQL 5.1 之前也不支持索引。Archive 引擎會緩存所有的寫并利用 zlib 對插入的行進行壓縮,所以比 MyISAM 表的磁盤 I/0 更少。但是每次 SELECT查詢都需要執行全表掃描。所以 Archive 表適合日志和數據采集類應用,這類應用做數據分析時往往需要全表掃描。或者在一些需要更快速的INSERT操作的場合下也可以使用。
????????Archive 引擎支持行級鎖和專用的緩沖區,所以可以實現高并發的插入。在一個查詢開始直到返回表中存在的所有行數之前,Archive 引擎會阻止其他的 SELECT執行,以實現一致性讀。另外,也實現了批量插入在完成之前對讀操作是不可見的。這種機制模仿了事務和 MVCC 的一些特性,但 Archive 引擎不是一個事務型的引擎,而是一個針對高速插入和壓縮做了優化的簡單引擎。
Blackhole引擎
????????Blackhole 引擎沒有實現任何的存儲機制,它會丟棄所有插入的數據,不做任何保存。但是服務器會記錄 Blackhole表的日志,所以可以用于復制數據到備庫,或者只是簡單地記錄到日志。這種特殊的存儲引擎可以在一些特殊的復制架構和日志審核時發揮作用但這種應用方式我們碰到過很多問題,因此并不推薦。
CSV 引擎
????????CSV 引擎可以將普通的 CSV 文件(逗號分割值的文件)作為 MySQL的表來處理,但這種表不支持索引。CSV引擎可以在數據庫運行時拷入或者拷出文件。可以將 Excel等電子表格軟件中的數據存儲為CSV 文件,然后復制到MySQL數據目錄下,就能在MySQL中打開使用。同樣,如果將數據寫入到一個 CSV 引擎表,其他的外部程序也能立即從表的數據文件中讀取 CSV格式的數據。因此CSV 引擎可以作為一種數據交換的機制,非常有用。
Federated引擎
????????Federated 引擎是訪問其他 MySQL服務器的一個代理,它會創建一個到遠程 MySQL 服務器的客戶端連接,并將查詢傳輸到遠程服務器執行,然后提取或者發送需要的數據最初設計該存儲引擎是為了和企業級數據庫如Microsoft SQL Server 和 Oracle 的類似特性競爭的,可以說更多的是一種市場行為。盡管該引擎看起來提供了一種很好的跨服務器的靈活性,但也經常帶來問題,因此默認是禁用的。MariaDB 使用了它的一個后續改進版本,叫做 Federatedx。
Memory 引擎
????????如果需要快速地訪問數據,并且這些數據不會被修改,重啟以后丟失也沒有關系,那么使用 Memory 表(以前也叫做 HEAP表)是非常有用的。Memory 表至少比 MyISAM 表要快一個數量級,因為所有的數據都保存在內存中,不需要進行磁盤I/O。Memory 表的結構在重啟以后還會保留,但數據會丟失。
Memroy 表在很多場景可以發揮好的作用
1、用于查找(lookup)或者映射(mapping)表,例如將郵編和州名映射的表。
2、用于緩存周期性聚合數據(periodically aggregated data)的結果。
3、用于保存數據分析中產生的中間數據
????????Memory 表支持 Hash索引,因此査找操作非常快。雖然 Memory 表的速度非常快,但還是無法取代傳統的基于磁盤的表。Memroy表是表級鎖,因此并發寫入的性能較低。它不支持 BLOB 或 TEXT類型的列,并且每行的長度是固定的,所以即使指定了 VARCHAR列,實際存儲時也會轉換成CHAR,這可能導致部分內存的浪費(其中一些限制在 Percona版本已經解決)。
????????如果 MySQLL在執行查詢的過程中需要使用臨時表來保存中間結果,內部使用的臨時表就是 Memory表。如果中間結果太大超出了 Memory表的限制,或者含有 BLOB 或 TEXT字段,則臨時表會轉換成 MyISAM 表。
4.4、選擇合適的引擎
????????這么多存儲引擎,我們怎么選擇?大部分情況下,InnoDB 都是正確的選擇,所以 Oracle在 MySQL 5.5 版本時終于將 InnoDB 作為默認的存儲引擎了。對于如何選擇存儲引擎可以簡單地歸納為一句話:“除非需要用到某些 InnoDB 不具備的特性,并且沒有其他辦法可以替代,否則都應該優先選擇 InnoDB 引擎”。例如,如果要用到全文索引,建議優先考慮 InnoDB 加上 Sphinx的組合,而不是使用支持全文索引的 MyISAM。當然,如果不需要用到 InnoDB 的特性,同時其他引擎的特性能夠更好地滿足需求,也可以考慮-下其他存儲引擎。舉個例子,如果不在乎可擴展能力和并發能力,也不在乎崩潰后的數據丟失問題,卻對 InnoDB 的空間占用過多比較敏感,這種場合下選擇 MyISAM 就比較合適。
????????除非萬不得已,否則建議不要混合使用多種存儲引擎,否則可能帶來一系列復雜的問題以及一些潛在的 bug 和邊界問題。存儲引擎層和服務器層的交互已經比較復雜,更不用說混合多個存儲引擎了。至少,混合存儲對一致性備份和服務器參數配置都帶來了一些困難。
如果應用需要不同的存儲引擎,請先考慮以下幾個因素。
事務
????????如果應用需要事務支持,那么InnoDB(或者 XtraDB)是目前最穩定并且經過驗證的選擇。如果不需要事務,并且主要是 SELECT和 INSERT操作,那么 MyISAM 是不錯的選擇。一般日志型的應用比較符合這一特性。
備份
????????備份的需求也會影響存儲引擎的選擇。如果可以定期地關閉服務器來執行備份,那么備份的因素可以忽略。反之,如果需要在線熱備份,那么選擇 InnoDB 就是基本的要求。
崩潰恢復
????????數據量比較大的時候,系統崩潰后如何快速地恢復是一個需要考慮的問題。相對而言MyISAM 崩潰后發生損壞的概率比 InnoDB 要高很多,而且恢復速度也要慢。因此,即使不需要事務支持,很多人也選擇 InnoDB 引擎,這是一個非常重要的因素。
特有的特性
????????最后,有些應用可能依賴一些存儲引擎所獨有的特性或者優化,比如很多應用依賴聚簇索引的優化。另外,MySQL中也只有 MyISAM 支持地理空間搜索。如果一個存儲引擎擁有一些關鍵的特性,同時卻又缺乏一些必要的特性,那么有時候不得不做折中的考慮,或者在架構設計上做一些取舍。某些存儲引擎無法直接支持的特性有時候通過變通也可以滿足需求。
5、總結
????????MySQL擁有分層的架構。上層是服務器層的服務和查詢執行引擎,下層則是存儲引擎。雖然有很多不同作用的插件 API,但存儲引擎 API還是最重要的。如果能理解 MySQL在存儲引擎和服務層之間處理査詢時如何通過 API來回交互,就能抓住 MySOL的核心基礎架構的精髓。
????????MySQL 最初基于ISAM 構建(后來被 MyISAM 取代),其后陸續添加了更多的存儲引擎和事務支持。MySOL有一些怪異的行為是由于歷史遺留導致的。例如,在執行 ALTERTABLE 時,MySOL提交事務的方式是由于存儲引擎的架構直接導致的,并且數據字典也保存在.fm文件中(這并不是說InnoDB會導致ALTER變成非事務型的。對于InnoDB來說所有的操作都是事務)。
?