一、基本概念
MySQL中有存儲引擎的概念,每張表可以對應一種存儲引擎。在使用者看來,表就是用來存取數據,而底層數據在磁盤上的組織、查詢數據時如何索引、表對使用者支持的功能等則由該表對應的存儲引擎來做出規範。
不同的存儲引擎有不同的特性,包括存儲空間大小限制、支持的功能、存取速度、空間利用率也不盡相同,在創建表時,用戶可針對不同的業務需求,自由選擇最適合的存儲引擎,這種插件式存儲引擎是MySQL數據庫最重要的特徵之一。
可通過show engines來查看數據庫支持的引擎(下面是Server version: 5.5.50 MySQL Community Server (GPL)):
mysql> show engines\G
*************************** 1. row ***************************
Engine: FEDERATED
Support: NO
Comment: Federated MySQL storage engine
Transactions: NULL
XA: NULL
Savepoints: NULL
*************************** 2. row ***************************
Engine: MRG_MYISAM
Support: YES
Comment: Collection of identical MyISAM tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 3. row ***************************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 4. row ***************************
Engine: BLACKHOLE
Support: YES
Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
XA: NO
Savepoints: NO
*************************** 5. row ***************************
Engine: CSV
Support: YES
Comment: CSV storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 6. row ***************************
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 7. row ***************************
Engine: ARCHIVE
Support: YES
Comment: Archive storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 8. row ***************************
Engine: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
*************************** 9. row ***************************
Engine: PERFORMANCE_SCHEMA
Support: YES
Comment: Performance Schema
Transactions: NO
XA: NO
Savepoints: NO
9 rows in set (0.01 sec)
在創建表時,若不指定存儲引擎,則使用默認存儲引擎,MySQL中默認參數均有對應的變量名,可以通過
show variables [like 'pattren'];
來顯示,要查看默認存儲引擎,可以這樣:
mysql> show variables like '%engine%';
+---------------------------+--------+
| Variable_name | Value |
+---------------------------+--------+
| default_storage_engine | InnoDB |
| engine_condition_pushdown | ON |
| storage_engine | InnoDB |
+---------------------------+--------+
其中default_storage_engine即爲默認存儲引擎。
- 創建一張未指定存儲引擎的表:
create table if not exists without_engin(
`id` int not null primary key auto_increment
)charset utf8;
可通過show create table 語句查詢這張表的存儲引擎:
mysql> show create table without_engin\G
*************************** 1. row ***************************
Table: without_engin
Create Table: CREATE TABLE `without_engin` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
其中ENGINE=InnoDB顯示該表的存儲引擎爲InnoDB,即用的默認引擎。
- 創建表時指定存儲引擎:
create table with_engin(
id int
)engine=MyISAM charset=utf8;
查看:
mysql> show create table with_engin\G
*************************** 1. row ***************************
Table: with_engin
Create Table: CREATE TABLE `with_engin` (
`id` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
存儲引擎爲MyISAM。
- 修改表的存儲引擎
alter table with_engin engine = innodb;
查看:
mysql> show create table with_engin\G
*************************** 1. row ***************************
Table: with_engin
Create Table: CREATE TABLE `with_engin` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
二、各種存儲引擎特性
各存儲引擎特性如下表:
特點 | MyISAM | InnoDB | MEMORY | MERGE | NDB |
---|---|---|---|---|---|
存儲限制 | 有 | 64TB | 有 | 沒有 | 有 |
事務安全 | 支持 | ||||
鎖機制 | 表鎖 | 行鎖 | 表鎖 | 表鎖 | 表鎖 |
B樹索引 | 支持 | 支持 | 支持 | 支持 | 支持 |
哈希索引 | 支持 | ||||
全文索引 | 支持 | ||||
集羣索引 | 支持 | ||||
數據緩存 | 支持 | 支持 | 支持 | ||
索引緩存 | 支持 | 支持 | 支持 | 支持 | 支持 |
數據可壓縮 | 支持 | ||||
空間使用 | 低 | 高 | N/A | 低 | 低 |
內存使用 | 低 | 高 | 中等 | 低 | 高 |
批量插入速度 | 高 | 低 | 高 | 高 | 高 |
支持外鍵 | 支持 |
可以看到不同的存儲引擎可以提供不同的功能、存取性能,所以在設計表的時候,要根據實際的應用場景,選擇合適的存儲引擎以優化系統性能。接下來主要MyISAM、InnoDB、MEMORY和MERGE。
1.MyISAM
特性:不支持事務、不支持外鍵、插入速度快、支持全文索引。
優勢:訪問速度快。
適用場景:1.對事務完整性沒有要求 2.以插入和查詢爲主的應用。
存儲方式:每個使用MyISAM引擎穿件的表在磁盤上存儲成3個文件,其文件名與表名相同,擴展名分別爲
- .frm (存儲表定義)
- .MYD(存儲數據)
- .MYI(存儲索引)
我們創建一張表,再插入數據
create table with_myisam_engin(
id int not null primary key auto_increment
)engine=MyISAM charset=utf8;
mysql> insert into with_myisam_engin values (null), (null);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from with_myisam_engin;
+----+
| id |
+----+
| 1 |
| 2 |
+----+
想要查看數據文件的位置,可通過以下命令:
mysql> show global variables like "%datadir%"
-> ;
+---------------+---------------------------------------------+
| Variable_name | Value |
+---------------+---------------------------------------------+
| datadir | C:\ProgramData\MySQL\MySQL Server 5.5\Data\ |
+---------------+---------------------------------------------+
這裏的ProgramData可能找不到,因爲是隱藏文件,可以設置顯示隱藏文件找到該文件夾,到該文件夾下,可以看到
其中的每個文件夾都對應我們的一個database,剛纔創建的表在以prac命名的datebase下,表名爲with_myisam_engin
三個文件的數據均是以二進制形式存儲,表中已經插入數據1、2,因爲數據單獨存在於.MYD文件中,可以查看下該文件中的內容
可以看到01 02兩個值。因爲三個文件分別保存了表的結構、數據、存儲定義,可以將這三個文件複製到其他數據庫對應的文件夾下,便可以在其他數據庫訪問該表,這也是使用MyISAM存儲引擎時一種可用的備份方式。
也可將數據文件和索引文件可以放到不同的目錄,平均分配I/O,獲得更快的速度,指定索引文件盒數據文件的路徑,需要在創建表的時候通過DATA DIRECTORY 和 INDEX DIRECTORY語句,這裏指定的路徑必須要是絕對路徑,並且具有訪問權限(寫的權限),筆者在prac文件夾下創建indexs和datas兩個文件夾,並通過以下語句創建一張MyISAM引擎表,指定索引文件、數據文件位置。
create table with_myisam_engin2(
id int not null primary key auto_increment
)engine=MyISAM DATA DIRECTORY='C:/ProgramData/MySQL/MySQL Server 5.5/data/prac/datas'
INDEX DIRECTORY='C:/ProgramData/MySQL/MySQL Server 5.5/data/prac/indexs' charset=utf8;
在windows下面指定文件夾的選項是被忽略的(mysql5.5上,其他版本不知道,在mysql的bug提交網站上可以看到這部分信息
https://bugs.mysql.com/bug.php?id=77773)
)
存儲格式:MyISAM支持三種不同的存儲格式:
- 靜態(固定長度)表:默認存儲格式,字段是非變長字段,這樣每個記錄都是固定長度的,這種存儲方式的優點是存儲迅速,容易緩存,出現故障容易恢復;缺點是佔用的空間比動態的多。靜態表的數據在存儲時會按照列的寬度定義補足空格,但是在應用訪問的時候並不會得到這些空格,這些空格在返回給應用之前已經去掉,因爲補齊主要是在後面補,所以如果插入的數據尾部本身有空格,再次查詢時會丟掉。
- 動態表,包含變長字段,記錄不是固定長度的,這樣存儲的優點是佔用空間相對較少,但是頻繁的更新和刪除記錄會產生碎片,需要定期執行OPTIMIZE TABLE語句或myisamchk-r命令來改善性能,並且在出現故障時恢復相對比較困難。
- 壓縮表由myisampack工具創建,佔據非常小的磁盤空間。因爲每條記錄是被單獨壓縮的,所以只有非常小的訪問開支。
上面提到的myisamchk、myisampack均位於MySQL的暗轉目錄下的bin文件夾下,關於靜態表丟失空格可參看下面的例子
create table lost_space(
name varchar(20) not null
)engine=MyISAM charset=utf8;
insert into lost_space values (" 123"),("123 "),("1 2 3");
select * , length(name) from lost_space;
顯示結果:
+-------+--------------+
| name | length(name) |
+-------+--------------+
| 123 | 4 |
| 123 | 4 |
| 1 2 3 | 5 |
+-------+--------------+
(參考資料:《深入淺出MySQL》)