mysql 引擎 MyISAM 和 InnoDB 知识点

319 阅读8分钟

MyISAM 和 InnoDB 的区别

InnoDB 支持事务,MyISAM 不支持事务。这是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一;

InnoDB 支持外键,而 MyISAM 不支持。对一个包含外键的 InnoDB 表转为 MYISAM 会失败;

InnoDB 是聚集索引,MyISAM 是非聚集索引。

聚簇索引的文件存放在主键索引的叶子节点上,因此 InnoDB 必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而 MyISAM 是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。

InnoDB 不保存表的具体行数,执行 select count(*) from table 时需要全表扫描。而MyISAM 用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;

InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁。一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限。这也是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一;

如何选择

是否要支持事务,如果要请选择 InnoDB,如果不需要可以考虑 MyISAM;

如果表中绝大多数都只是读查询,可以考虑 MyISAM,如果既有读写也挺频繁,请使用InnoDB。

系统奔溃后,MyISAM恢复起来更困难,能否接受,不能接受就选 InnoDB;

MySQL5.5版本开始Innodb已经成为Mysql的默认引擎(之前是MyISAM),说明其优势是有目共睹的。如果你不知道用什么存储引擎,那就用InnoDB,至少不会差。

MyISAM: 在MySQL 5.1 及之前的版本,MyISAM是默认引擎。MyISAM提供的大量的特性,包括全文索引、压缩、空间函数(GIS)等,但MyISAM并不支持事务以及行级锁,而且一个毫无疑问的缺陷是崩溃后无法安全恢复。正是由于MyISAM引擎的缘故,即使MySQL支持事务已经很长时间了,在很多人的概念中MySQL还是非事务型数据库。尽管这样,它并不是一无是处的。对于只读的数据,或者表比较小,可以忍受修复操作,则依然可以使用MyISAM(但请不要默认使用MyISAM,而是应该默认使用InnoDB)

InnoDB: MySQL默认的事务型引擎,也是最重要和使用最广泛的存储引擎。它被设计成为大量的短期事务,短期事务大部分情况下是正常提交的,很少被回滚。InnoDB的性能与自动崩溃恢复的特性,使得它在非事务存储需求中也很流行。除非有非常特别的原因需要使用其他的存储引擎,否则应该优先考虑InnoDB引擎。

存储结构

MyISAM: 每个MyISAM在磁盘上存储成三个文件。分别为:表定义文件、数据文件、索引文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。

InnoDB: 所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。

存储空间

MyISAM: MyISAM支持三种不同的存储格式:静态表(默认,但是注意数据末尾不能有空格,会被去掉)、动态表、压缩表。当表在创建之后并导入数据之后,不会再进行修改操作,可以使用压缩表,极大的减少磁盘的空间占用。

InnoDB: 需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。

可移植性、备份及恢复

MyISAM: 数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作。 InnoDB: 免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了。

事务支持

MyISAM:

强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。

InnoDB:

提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。

AUTO_INCREMENT

MyISAM: 可以和其他字段一起建立联合索引。引擎的自动增长列必须是索引,如果是组合索引,自动增长可以不是第一列,他可以根据前面几列进行排序后递增。

InnoDB: InnoDB中必须包含只有该字段的索引。引擎的自动增长列必须是索引,如果是组合索引也必须是组合索引的第一列。

表锁差异

MyISAM:

只支持表级锁,用户在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。

InnoDB:

支持事务和行级锁,是innodb的最大特色。行锁大幅度提高了多用户并发操作的新能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的

在MySQL 5.5版本前,默认的存储引擎为MyISAM。在那之后MySQL的默认存储引擎改为InnoDB。

这两个存储引擎都是非常经典的存储引擎,因此在面试中也被经常拿来做对比。

这两个存储引擎既有很多的不同点,但是也有一些相同点。下面详细介绍一下。

  1. MyISAM不支持事务,InnoDB支持事务。由于MyISAM在很长一段时间内是MySQL的默认存储引擎,所以在很多人的印象中MySQL是不支持事务的数据库。实际上,InnoDB是一个性能良好的事务性引擎。它实现了四个标准的隔离级别,默认的隔离级别为可重复读(REPEATABLE READ),并通过间隙锁策略来防止幻读的出现。此外它还通过多版本并发控制(MVCC)来支持高并发。

  2. 对表的行数查询的支持不同。MyISAM内置了一个计数器来存储表的行数。执行 select count() 时直接从计数器中读取,速度非常快。而InnoDB不保存这些信息,执行 select count()需要全表扫描。当表中数据量非常大的时候速度很慢。

  3. 锁的粒度不同。MyISAM仅支持表锁。每次操作锁住整张表。这种处理方式一方面加锁的开销比较小,且不会出现死锁,但另一方面并发性能较差。InnoDB支持行锁。每次操作锁住一行数据,一方面行级锁在每次获取锁和释放锁的操作需要消耗比表锁更多的资源,速度较慢,且可能发生死锁,但是另一方面由于锁的粒度较小,发生锁冲突的概率也比较低,并发性较好。此外,即使是使用了InnoDB存储引擎,但如果MySQL执行一条sql语句时不能确定要扫描的范围,也会锁住整张表。

  4. 对主键的要求不同。MyISAM允许没有主键的表存在。而如果在建表时没有显示的指定主键,InnoDB就会为每一行数据自动生成一个6字节的ROWID列,并以此做为主键。这种主键对用户不可见。InnoDB对主键采取这样的策略是与它的数据和索引的组织方式有关的,下文会讲到。

  5. 数据和索引的组织方式不同。MyISAM将索引和数据分开进行存储。索引存放在.MYI文件中,数据存放在.MYD文件中。索引中保存了相应数据的地址。以表名+.MYI文件分别保存。 InnoDB的主键索引树的叶子节点保存主键和相应的数据。其它的索引树的叶子节点保存的是主键。也正是因为采取了这种存储方式,InnoDB才强制要求每张表都要有主键。

  6. 对AUTO_INCREMENT的处理方式不一样。如果将某个字段设置为INCREMENT,InnoDB中规定必须包含只有该字段的索引。但是在MyISAM中,也可以将该字段和其他字段一起建立联合索引。

  7. delete from table的处理方式不一样。MyISAM会重新建立表。InnoDB不会重新建立表,而是一行一行的删除。因此速度非常慢。推荐使用truncate table,不过需要用户有drop此表的权限。

  8. MyISAM崩溃后无法安全恢复,InnoDB支持崩溃后的安全恢复。InnoDB实现了一套完善的崩溃恢复机制,保证在任何状态下(包括在崩溃恢复状态下)数据库挂了,都能正常恢复。

  9. MyISAM不支持外键,InnoDB支持外键。10. 缓存机制不同。MyISAM仅缓存索引信息,而不缓存实际的数据信息。而InnoDB不仅缓存索引信息,还会缓存数据信息。其将数据文件按页读取到缓冲池,然后按最近最少使用的算法来更新数据。