一、基本概念
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》)