存儲引擎層
從體系結構圖中可以發現,MySQL資料庫差別于其他資料庫的最重要的一個特點就是其插件式的表存儲引擎。MySQL插件式的存儲引擎架構提供了一系列标準的管理和服務支援,這些标準與存儲引擎本身無關,可能是每個資料庫系統本身都必需的,如SQL分析器和優化器等,而存儲引擎是底層實體結構和實際檔案讀寫的實作,每個存儲引擎開發者可以按照自己的意願來進行開發。需要特别注意的是,存儲引擎是基于表的,而不是資料庫。
插件式存儲引擎的好處是,每個存儲引擎都有各自的特點,能夠根據具體的應用建立不同存儲引擎表。由于MySQL資料庫的開源特性,使用者可以根據MySQL預定義的存儲引擎接口編寫自己的存儲引擎。若使用者對某一種存儲引擎的性能或功能不滿意,可以通過修改源碼來得到想要的特性,這就是開源帶給我們的友善與力量。
由于MySQL資料庫開源特性,存儲引擎可以分為MySQL官方存儲引擎和第三方存儲引擎。有些第三方存儲引擎很強大,如大名鼎鼎的InnoDB存儲引擎(最早是第三方存儲引擎,後被Oracle收購),其應用就極其廣泛,甚至是MySQL資料庫OLTP(Online Transaction Processing線上事務處理)應用中使用最廣泛的存儲引擎。
2.1.3.1.MySQL官方引擎概要
InnoDB存儲引擎
InnoDB是MySQL的預設事務型引擎,也是最重要、使用最廣泛的存儲引擎。它被設計用來處理大量的短期(short-lived)事務,短期事務大部分情況是正常送出的,很少會被復原。InnoDB的性能和自動崩潰恢複特性,使得它在非事務型存儲的需求中也很流行。除非有非常特别的原因需要使用其他的存儲引擎,否則應該優先考慮InnoDB引擎。如果要學習存儲引擎,InnoDB也是一個非常好的值得花最多的時間去深入學習的對象,收益肯定比将時間平均花在每個存儲引擎的學習上要高得多。是以InnoDB引擎也将是我們學習的重點。
MylSAM存儲引擎
在MySQL 5.1及之前的版本,MyISAM是預設的存儲引擎。MyISAM提供了大量的特性,包括全文索引、壓縮、空間函數(GIS)等,但MyISAM不支援事務和行級鎖,而且有一個毫無疑問的缺陷就是崩潰後無法安全恢複。盡管MyISAM引擎不支援事務、不支援崩潰後的安全恢複,但它絕不是一無是處的。對于隻讀的資料,或者表比較小、可以忍受修複(repair)操作,則依然可以繼續使用MyISAM(但請不要預設使用MyISAM,而是應當預設使用InnoDB)。但是MyISAM對整張表加鎖,而不是針對行。讀取時會對需要讀到的所有表加共享鎖,寫入時則對表加排他鎖。MyISAM很容易因為表鎖的問題導緻典型的的性能問題。其他的存儲引擎省略
選擇合适的引擎
這麼多存儲引擎,我們怎麼選擇?大部分情況下,InnoDB都是正确的選擇,是以在MySQL 5.5版本将InnoDB作為預設的存儲引擎了。對于如何選擇存儲引擎,可以簡單地歸納為一句話:“除非需要用到某些InnoDB不具備的特性,并且沒有其他辦法可以替代,否則都應該優先選擇InnoDB引擎”。比如,MySQL中隻有MyISAM支援地理空間搜尋。
當然,如果不需要用到InnoDB的特性,同時其他引擎的特性能夠更好地滿足需求,也可以考慮一下其他存儲引擎。舉個例子,如果不在乎可擴充能力和并發能力,也不在乎崩潰後的資料丢失問題,卻對InnoDB的空間占用過多比較敏感,這種場合下選擇MyISAM就比較合适。
除非萬不得已,否則建議不要混合使用多種存儲引擎,否則可能帶來一系列複雜的問題,以及一些潛在的bug和邊界問題。存儲引擎層和伺服器層的互動已經比較複雜,更不用說混合多個存儲引擎了。至少,混合存儲對一緻性備份和伺服器參數配置都帶來了一些困難。
表引擎的轉換
有很多種方法可以将表的存儲引擎轉換成另外一種引擎。每種方法都有其優點和缺點。常用的有三種方法
ALTER TABLE
将表從一個引擎修改為另一個引擎最簡單的辦法是使用ALTER TABLE 語句。下面的語句将mytable的引擎修改為InnoDB :
ALTER TABLE mytable ENGINE = InnoDB;
上述文法可以适用任何存儲引擎。但需要執行很長時間,在實作上,MySQL會按行将資料從原表複制到一張新的表中,在複制期間可能會消耗系統所有的I/O能力,同時原表上會加上讀鎖。是以,在繁忙的表上執行此操作要特别小心。
導出與導入
還可以使用mysqldump工具将資料導出到檔案,然後修改檔案中CREATE TABLE語句的存儲引擎選項,注意同時修改表名,因為同一個資料庫中不能存在相同的表名,即使它們使用的是不同的存儲引擎。
CREATE和 SELECT
先建立一個新的存儲引擎的表,然後利用INSERT…SELECT文法來導資料:
CREATE TABLE innodb_table LIKE myisam_table;
ALTER TABLE innodb_table ENGINE=InnoDB;
INSERT INTO innodb_table SELECT * FROM myisam_table;
如果資料量很大,則可以考慮做分批處理,針對每一段資料執行事務送出操作。
檢查MySQL的引擎
看我的MySQL現在已提供什麼存儲引擎:
show engines;
看我的MySQL目前預設的存儲引擎:
show variables like '%storage_engine%';