MySQL 5.0 之後的版本支援的儲存引擎包括 MyISAM, InnoDB, MEMORY, CSV …等

其中 InnoDB 屬於交易安全表(支持交易,行級鎖定,外鍵和表加密)

MyISAM、MEMORY、CSV則屬於非交易安全表。

將目前支援的儲存引擎列出來,就能看到個引擎的支援狀況:

> SHOW ENGINES \G
...
*************************** 2. row ***************************
      Engine: InnoDB
     Support: DEFAULT
     Comment: Percona-XtraDB, Supports transactions, row-level locking, foreign keys and encryption for tables
Transactions: YES
          XA: YES
  Savepoints: YES
*************************** 3. row ***************************
      Engine: MEMORY
     Support: YES
     Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 4. row ***************************
      Engine: MyISAM
     Support: YES
     Comment: MyISAM storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
...
8 rows in set (0.00 sec)

在 MySQL 5.5 之前,預設的儲存引擎是 MyISAM

MySQL 5.5 之後,預設搜尋引擎則設定為 InnoDB

如果要修改這個預設,可以直接修改 default-table-type

特性

InnoDB 儲存引擎具有交易安全的功能,因此具備了提交、回滾(rollback)以及崩壞修復能力,著重於安全性及功能面

因此,對於寫入速度相對於MyISAM 差一點,並且InnoDB在保存資料時,會占用較多的空間來管理資料及索引。

接下來介紹InnoDB 的一些特性:

AUTO INCREATMENT 欄位必須是索引

InnoDB 的 AUTO_INCREMENT 欄位必須符合以下條件

  • 必須是索引 (INDEX or PRIMARY KEY)
  • 若是組合索引,則必須是組合索引的第一列

可以設定外鍵

InnoDB 是 MySQL 唯一支援外鍵的儲存引擎

範例:

這裡透過國家及城市來說明外鍵的用法

我們先建立好 country 及 city 的資料表

country

MariaDB [example]> CREATE TABLE country( 
	country_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, 
	country VARCHAR(50) NOT NULL, 
	last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
	PRIMARY KEY(country_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Query OK, 0 rows affected (0.05 sec)

MariaDB [example]> desc country;
+-------------+----------------------+------+-----+-------------------+-----------------------------+
| Field       | Type                 | Null | Key | Default           | Extra                       |
+-------------+----------------------+------+-----+-------------------+-----------------------------+
| country_id  | smallint(5) unsigned | NO   | PRI | NULL              | auto_increment              |
| country     | varchar(50)          | NO   |     | NULL              |                             |
| last_update | timestamp            | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------------+----------------------+------+-----+-------------------+-----------------------------+
3 rows in set (0.04 sec)

city 在 city 資料表中,設定外鍵連結 FOREIGN KEY(country_id)

並且,設定了一些串聯式條件:

ON DELETE RESTRICT : 父表 counrty 具有存在 city 外鍵時,無法單獨刪除 country 內容

ON UPDATE CASCADE : 父表 counrty 執行更新時,city 要同時更新

如果沒有指定ON DELETE 或ON UPDATE,NO ACTION 將會是預設值

MariaDB [example]> CREATE TABLE city( 
	city_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, 
	city VARCHAR(50) NOT NULL, 
	country_id SMALLINT UNSIGNED NOT NULL, 
	last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
	PRIMARY KEY (city_id), 
	KEY idx_fk_country_id (country_id),  
	FOREIGN KEY(country_id) 
	REFERENCES country (country_id) 
	ON DELETE RESTRICT 
  ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Query OK, 0 rows affected (0.06 sec)
MariaDB [example]> desc city;
+-------------+----------------------+------+-----+-------------------+-----------------------------+
| Field       | Type                 | Null | Key | Default           | Extra                       |
+-------------+----------------------+------+-----+-------------------+-----------------------------+
| city_id     | smallint(5) unsigned | NO   | PRI | NULL              | auto_increment              |
| city        | varchar(50)          | NO   |     | NULL              |                             |
| country_id  | smallint(5) unsigned | NO   | MUL | NULL              |                             |
| last_update | timestamp            | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------------+----------------------+------+-----+-------------------+-----------------------------+
4 rows in set (0.02 sec)

插入幾筆資料

MariaDB [example]> INSERT INTO country(`country`) VALUES('Taiwan'), ('China');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

MariaDB [example]> SELECT * FROM country;
+------------+---------+---------------------+
| country_id | country | last_update         |
+------------+---------+---------------------+
|          1 | Taiwan  | 2018-02-28 15:31:12 |
|          2 | China   | 2018-02-28 15:31:12 |
+------------+---------+---------------------+
2 rows in set (0.00 sec)

MariaDB [example]> INSERT INTO city(`city`,`country_id`) VALUES('Taipei',1), ('Beijing',2);
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

MariaDB [example]> SELECT * FROM city;
+---------+---------+------------+---------------------+
| city_id | city    | country_id | last_update         |
+---------+---------+------------+---------------------+
|       1 | Taipei  |          1 | 2018-02-28 15:32:47 |
|       2 | Beijing |          2 | 2018-02-28 15:32:47 |
+---------+---------+------------+---------------------+
2 rows in set (0.00 sec)

測試 ON DELETE RESTRICT 接下來測試看看,單獨刪除 country 因為有設定 ON DELETE RESTRICT,因此在具有子對應紀錄的情況,無法單獨刪除 country 資料

MariaDB [example]> DELETE FROM country WHERE country_id = 1;

ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`example`.`city`, CONSTRAINT `city_ibfk_1` FOREIGN KEY (`country_id`) REFERENCES `country` (`country_id`) ON UPDATE CASCADE)

測試 ON UPDATE CASCADE 更新 country 的 id,再檢查 country 與 city 欄位值 因為有設定 ON UPDATE CASCADE,因此更新 country 資料也會同時更新子表單對應資料

MariaDB [example]> SELECT * FROM country;
+------------+---------+---------------------+
| country_id | country | last_update         |
+------------+---------+---------------------+
|          2 | China   | 2018-02-28 15:31:12 |
|          3 | Taiwan  | 2018-02-28 15:53:35 |
+------------+---------+---------------------+
2 rows in set (0.00 sec)

MariaDB [example]> SELECT * FROM city;
+---------+---------+------------+---------------------+
| city_id | city    | country_id | last_update         |
+---------+---------+------------+---------------------+
|       1 | Taipei  |          1 | 2018-02-28 15:32:47 |
|       2 | Beijing |          3 | 2018-02-28 15:32:47 |
+---------+---------+------------+---------------------+
2 rows in set (0.00 sec)

暫時關閉外鍵約束

有時需要暫時忽略外鍵的束縛,直接操作時,可以透過下方的指令將外鍵檢查關閉

SET FOREIGN_KEY_CHECKS=0;

若要重新啟用外鍵檢查,則再將值設為1

SET FOREIGN_KEY_CHECKS=1;

範例: 直接刪除具有子對應紀錄的父層資料,會顯示錯誤 接著把 SET FOREIGN_KEY_CHECKS=0; 設定完成後 就能成功刪除父層資料 再重新開啟 SET FOREIGN_KEY_CHECKS=1; 外鍵檢查功能 就恢復無法直接刪除具有子對應紀錄的父層資料

MariaDB [example]> DELETE FROM country WHERE country_id = 3;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`example`.`city`, CONSTRAINT `city_ibfk_1` FOREIGN KEY (`country_id`) REFERENCES `country` (`country_id`) ON UPDATE CASCADE)
MariaDB [example]> SET FOREIGN_KEY_CHECKS=0;
Query OK, 0 rows affected (0.00 sec)

MariaDB [example]> DELETE FROM country WHERE country_id = 3;
Query OK, 1 row affected (0.00 sec)

MariaDB [example]> SET FOREIGN_KEY_CHECKS = 1;
Query OK, 0 rows affected (0.00 sec)

MariaDB [example]> DELETE FROM country WHERE country_id = 2;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`example`.`city`, CONSTRAINT `city_ibfk_1` FOREIGN KEY (`country_id`) REFERENCES `country` (`country_id`) ON UPDATE CASCADE)