MySQL 存儲引擎
在MySQL中有一個存儲引擎的概念,針對不同的存儲需求可以選擇最優的存儲引擎。
一、概述
MySQL 5.0 支持的存儲引擎包括MyISAM、InnoDB、BDB、MEMORY、MERGE、EXAMPLE、NDB Cluster、ARCHIVE、CSV、BLACKHOLE、FEDERATED等,其中InnoDB和BDB提供事務安全表,其他存儲引擎都是非事務安全表。
MySQL5.5之前的默認存儲是MyISAM,5.5之後是InnoDB。如果要修改默認的存儲引擎,可以在參數文件中設置default-table-type。在創建表時,可以通過增加engine關鍵字設置新建表的存儲引擎,例如:表auth_type
CREATE TABLE `auth_type` (
`id` int(11) NOT NULL,
`type_code` char(3) DEFAULT NULL COMMENT ‘授權類型編號‘,
`type_name` varchar(255) DEFAULT NULL COMMENT ‘授權類型名稱‘,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
CREATE TABLE `auth_user` (
`id` int(11) NOT NULL,
`user_name` varchar(30) DEFAULT NULL COMMENT ‘授權用戶名稱‘,
`token` char(64) DEFAULT NULL COMMENT ‘訪問授權token‘,
`created_at` timestamp NULL DEFAULT NULL COMMENT ‘記錄創建時間‘,
`updated_at` timestamp NULL DEFAULT NULL COMMENT ‘記錄最後修改時間‘,
`deleted_at` timestamp NULL DEFAULT NULL COMMENT ‘記錄刪除時間‘,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
也可以使用ALERT TABLE語句,將一個已經存在的表改成其他的存儲引擎。alert table auth_type engine = InnoDB
二、各種存儲引擎特性
先看下表各個存儲引擎之間的區別
特 點 | MyISAM | InnoDB | Memory | Merge | NDB |
存儲限制 | 有 | 64TB | 有 | 沒有 | 有 |
事務安全 | 支持 | ||||
鎖機制 | 表鎖 | 行鎖 | 表鎖 | 表鎖 | 行鎖 |
B樹索引 | 支持 | 支持 | 支持 | 支持 | 支持 |
哈希索引 | 支持 | 支持 | |||
全文索引 | 支持 | ||||
集群索引 | 支持 | ||||
數據緩存 | 支持 | 支持 | 支持 | ||
索引緩存 | 支持 | 支持 | 支持 | 支持 | 支持 |
數據可壓縮 | 支持 | ||||
空間使用 | 低 | 高 | N/A | 低 | 低 |
內存使用 | 低 | 高 | 中等 | 低 | 高 |
批量插入速度 | 高 | 低 | 高 | 高 | 高 |
支持外鍵 | 支持 |
下面將介紹最常用的4種存儲引擎:MyISAM、InnoDB、Memory和Merge。
1、MyISAM
MyISAM 不支持事務、不支持外鍵,其優勢是訪問的速度快,對事務的完整性沒有要求或者以SELECT\INSERT為主的應用基本上可以使用這個引擎來創建表。
每個MyISAM在磁盤上存儲成3個文件,其文件名都和表名相同,但擴展名分別是:
.frm(存儲表定義)
.MYD(MYData,存儲數據)
.MYI(MYIndex,存儲索引)
數據文件和索引文件可以放置在不同的目錄,平均分布IO,獲得更快的速度。
在創建表的時候通過DATA DIRECTORY和INDEX DIRECTORY語句指定數據文件和索引文件的路徑,該路徑需要絕對路徑,並且具有訪問權限。
MyISAM類型的表可能會被損壞,各種各樣的原因被損壞。損壞後的表可能不能被訪問,會提示需要修復或者返回錯誤結果。MyISAM類型的表提供了修復工具,
CHECK TABLE 語句用於檢查表的健康,REPAIR TABLE 語句用來修復一個損壞的表。表的損壞還可能導致數據庫的異常啟動,需要盡快修復並盡可能地確認損壞的原因。
MyISAM的表還支持3種不同的存儲格式,分別是:靜態(固定長度)表、動態表、壓縮表。
靜態表:表中的字段是非變長字段,這樣每個字段都是固定長度,如char(20)。這種存儲的優點是:存儲非常迅速,容易緩存,出現故障容易恢復;缺點是:占用的空間通常比動態表多。靜態表的數據存儲時會按給定的列寬度定義補足空格,但是應用訪問時並不會得到這些空格。
動態表:表中包含變長字段,比如varchar(20),記錄不是固定長度。哪怕只有一個字段是變長字段,也是動態表。這種存儲的優點是:占用的空間相對較少,但是頻繁地更新和刪除記錄會產生碎片,需要定期執行 OPTIMIZE TABLE 或者 myisamchk-r 命令來改善性能,並且在出現故障時恢復相對比較困難。
壓縮表:表由myisampack工具創建,占據非常小的磁盤空間。因為記錄是被單個壓縮的,所以只有非常小的開支。
2、InnoDB
InnoDB存儲引擎提供了具有提交、回滾和崩潰恢復能力的事務安全。但是對比MyISAM存儲引擎,InnoDB寫的處理效率差點,並且會占用更多的磁盤空間以保留數據和索引。
InnoDB存儲引擎的特點:
2.1、自動增長列
InnoDB表的自動增長可以手動插入,但是插入的值如果是空或者是0,則實際插入的將是自動增長後的值。例如:下表auth_user中,列id為自動增長列,通過AUTO_INCREMENT指定。
CREATE TABLE `auth_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(30) DEFAULT NULL COMMENT ‘授權用戶名稱‘,
`token` char(64) DEFAULT NULL COMMENT ‘訪問授權token‘,
`created_at` timestamp NULL DEFAULT NULL COMMENT ‘記錄創建時間‘,
`updated_at` timestamp NULL DEFAULT NULL COMMENT ‘記錄最後修改時間‘,
`deleted_at` timestamp NULL DEFAULT NULL COMMENT ‘記錄刪除時間‘,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=‘授權用戶表‘;
還可通過“ALTER TABLE auth_user AUTO_INCREMENT = n;”語句強制設置自動增長的初始值,默認從1開始,但是該強制的默認值是保留在內存中的,如果該值在使用之前數據庫重新啟動,那麽這個強制的默認值就會丟失,就需要在數據庫啟動後重新設置。
可以會用LAST_INSERT_ID()查詢當前線程最後插入記錄使用的值。如果一次插入多條記錄,那麽返回的是第一條記錄使用的自動增長值。
對於InnoDB表,自動增長列必須是索引。如果是組合索引,也必須是組合索引的第一列,但是對於MyISAM表,自動增長列可以是組合索引的其他列,這樣插入記錄後,自動增長列是按照組合索引的前列進行排序後遞增的。如:
CREATE TABLE `autoincre_demo` (
`id1` int(11) NOT NULL AUTO_INCREMENT,
`id2` int(11) NOT NULL,
`name` varchar(30) DEFAULT NULL COMMENT ‘名稱‘
index (`id1`,`id2`)
) ENGINE=MyISAM;
insert into `autoincre_demo`(`id2`,‘name‘) values(2,‘2‘),(3,‘3‘),(4,‘4‘);
結果是:select * from `autoincre_demo`;
id1 | id2 | name |
1 | 2 | 2 |
1 | 3 | 3 |
1 | 4 | 4 |
2 | 2 | 2 |
2 | 3 | 3 |
2 | 4 | 4 |
2.2、外鍵約束
MySQL支持外鍵的存儲引擎只有InnoDB,在創建外鍵的時候,要求父表必須有對應的索引,子表在創建外鍵的時候也會自動創建對應的索引。
在創建索引時,可以指定在刪除、更新附表時,對子表的相應操作,包括restrict、cascade、set null和no action。
restrict 和 no action相同,是指限制在子表有關聯記錄時父表不能更新。
cascade是指,父表在更新或刪除時,更新或者刪除子表對應記錄。
set null是指,父表在更新或者刪除時,子表對應的字段被set null。
當某個表被其他表創建了外鍵參照,那麽該表的對應索引或者主鍵禁止被刪除。
在導入多個表的數據時,如果需要忽略表之前的導入順序,可以暫時關閉外鍵的檢查;同樣,在執行LOAD DATA和ALTER TABLE操作的時候,可以通過暫時關閉外鍵約束來加快處理的速度,關閉的命令是“SET FOREING_KEY_CHECKS = 0;”,執行完成後,通過執行“SET FOREING_KEY_CHECKS = 1;”語句返回原狀。
2.3、存儲方式
InnoDB存儲表和索引有以下兩種方式。
使用共享表空間存儲,這種方式創建的表的表結構保存在.frm文件中,數據和索引保存在innod_data_home_dir和innod_data_file_path定義的表空間中,可以是多個文件。
使用多表空間存儲,這種方式創建的表的表結構保存在.frm文件中,但是每個表的數據和索引單獨保存在.ibd中。如果是個分區表,則每個分區對應單獨的.ibd文件,文件名是“表名+分區名”,可以在創建分區的時候指定每個分區的數據文件位置,以此來將表的IO均分在多個磁盤上。
要使用多表空間的存儲方式,需要設置參數innodb_file_per_table,並且重新啟動服務才可以生效,對於新建的表按照多表空間的方式創建,已有的表仍使用共享表空間存儲。如果將已有的多表空間方式修改回共享表空間的方式,則新建表會在共享表空間的創建,但已有的多表空間表仍然保存原來的存儲方式。
多表空間的數據文件沒有大小限制,不需要設置初始大小,也不需要設置文件的最大限制、擴展大小等參數。
對於使用多表空間特性的表,可以比較方便的進行單表備份和恢復操作,但是直接復制.ibd文件是不行的,因為沒有共享表的數據字典信息,直接復制的.ibd文件和.frm文件恢復時是不能被識別的,但是可以通過以下命令:
ALTER TABLE tbl_name DISCARD TABLESPACE;
ALTER TABLE tbl_name IMPORT TABLESPACE;
將備份恢復到數據庫,但是這只能恢復到表原來所在的數據庫中,不能恢復到其他的數據庫中。可以通過mysqldump和mysqlimport來將單表恢復到目標數據庫。
註意:即便在多表空間的存儲方式下,共享表空間仍然是必須的,InnoDB把內部數據詞典和在線重做日誌放在這個文件中。
3、Memory
Memory存儲引擎使用存在於內存中的內容來創建表。每個Memory表只實際上對應一個磁盤文件,格式是.frm。Memory類型的表訪問速度非常快,因為它的數據是放在內存中的,並且默認使用HASH索引,但是一旦服務關閉,表中的數據就會丟失。
在啟動MySQL服務的時候使用--init--file選項,把INSERT INTO ... SELECT 或LOAD DATA INFILE 這樣的語句放入這個文件中,就可以在服務啟動時從持久穩固的數據源裝載表。
服務器需要足夠內存來維持所有在同一時間使用的Memory表,當不再需要Memory表的內容之時,要釋放被Memory表使用的內存,應該執行DELETE FROM 或 TRUNCATE TABLE,或者整個的刪除表(使用DROP TABLE操作)。
每個Memory表中可以放置的數據量大小,受到max_heap_table_size系統變量的約束,這個系統變量的初始值是16MB,可以根據需要加大。此外,在定義Memory表的時候,可以通過MAX_ROWS子句指定表的最大行數。
Memory類型的存儲引擎主要應用於那些語句變化不頻繁的代碼表,或者作為統計操作的中間結果表,便於高效地對中間結果進行分析並得到最終的統計結果。對存儲引擎為Memory的表進行更新操作要謹慎,因為數據並沒有實際寫入到磁盤中,所以一定要對下次重啟服務後如何獲得這些修改的數據有所考慮。
4、Merge
Merge存儲引擎是一組MyISAM表的組合,這些MyISAM表必須結構完全相同,Merge表本身並沒有數據,對Merge類型的表可以進行查詢、更新、刪除,這些操作實際上是對內部的MyISAM表進行的。對於Merge類型表的插入操作,是通過INSERT_METHOD子句定義插入的表,可以有3個不同的值,使用FIRST或者LAST值使得插入操作被相應地作用在第一個或者最後一個表上,不定義這個子句或者定義為NO,表示不能對這個Merger表進行操作。
可以對Merge表進行DROP操作,這個操作只是刪除Merge的定義,對內部的表沒有任何的影響。
在磁盤上保留兩個文件,文件名以表的名字開始,一個.frm文件存儲表定義,另一個.mrg文件包含組合表的信息,包含Merge表由哪些表組成、插入新數據的依據。可以通過修改.mrg文件來修改Merge表,但是修改後要通過flush tables刷新。
Merger表和分區表的區別是,Merger表並不能智能地將記錄寫到對應的表中,而是寫入到使用FIRST或者LAST值指定的表中。但是分區表可以。通常我們使用Merger表來透明地對多個表進行查詢和更新操作,而這種按照時間記錄的操作日誌表則可以透明地進行插入操作。
三、如何選擇合適的存儲引擎
四、小結
MySQL 存儲引擎