MySQL存储引擎MyISAM和InnoDB详谈

一、概述

MySQL数据库支持多种存储引擎,包括MyISAM、InnoDB、MERGE、MEMORY(HEAP)、BDB(BerkeleyDB)、EXAMPLE、FEDERATED、ARCHIVE、CSV、BLACKHOLE等。

我们可以通过show engines指令查看自己系统安装的MySQL对引擎种类的支持:
在这里插入图片描述

还可以通过show variables like '%storage_engine%'指令查看MySQL默认使用的存储引擎,从下图看到我系统上MySQL默认存储引擎为InnoDB。
在这里插入图片描述

我的MySQL版本为5.7.32:
在这里插入图片描述
MyISAM是MySQL自带的存储引擎;InnoDB是第三方公司开发的,以插件的形式集成到MySQL。
5.5版之前,MyISAM是MySQL的默认数据库引擎;之后的版本MySQL默认使用更多的是InnoDB。

本文主要对常用的MyISAM和InnoDB进行探讨。


二、MyISAM和InnoDB详谈

1、比较

1、存储结构
1)MyISAM
每个MyISAM在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。
.frm:表结构文件
.MYD:数据文件
.MYI:索引文件

索引文件保存记录所在的数据文件的位置,通过读取索引文件获取到位置信息后,再通过读取数据文件快速取得数据。
在这里插入图片描述
2)InnoDB
只有两个文件:
.frm:表结构文件
.ibd:数据、索引文件

InnoDB采用了聚簇索引的方式实现B-Tree索引,聚簇索引的实现方式是将数据行和相邻主键紧凑地存入文件中。
InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。
在这里插入图片描述
InnoDB采用表空间(tablespace)来管理数据,存储表数据和索引。在mysql5.6.6之前采用的是共用表空间,之后版本采用单表空间。

  • 共用表空间:ibdata1、ibdata2存放位置是在Data文件夹内,所有表共用。
  • 单表空间:可以通过全局变量开启,开启后每个表都有一个对应的.ibd与其对应。
# When innodb_file_per_table is enabled (the default in 5.6.6 and higher), InnoDB stores the data and indexes for each newly created table
# in a separate .ibd file, rather than in the system tablespace.
innodb_file_per_table=1

可以通过show variables like '%innodb_file_per_table%'指令查看mysql是否开启单独表空间:
在这里插入图片描述
共用表空间和单表空间的优缺点:
1)单表空间
优点:
- 每个表都有自已独立的表空间。
- 每个表的数据和索引都会存在自已的表空间中。
- 可以实现单表在不同的数据库中移动。
- 空间可以回收(drop/truncate table方式操作表空间不能自动回收)。
- 对于使用独立表空间的表,不管怎么删除,表空间的碎片不会太严重的影响性能,而且还有机会处理。
缺点:
- 单表增加比共享空间方式更大。

2)共表空间
优点:
- 可以放表空间分成多个文件存放到各个磁盘上(表空间文件大小不受表大小的限制,如一个表可以分布在不同的文件上)。
- 其大小限制不再是文件大小的限制,而是其自身的限制。从Innodb的官方文档中可以看到,其表空间的最大限制为64TB。

缺点:
- 所有的数据和索引存放到一个文件中,将有一个很常大的文件,虽然可以把一个大文件分成多个小文件,但是多个表及索引在表空间中混合存储,这样对于一个表做了大量删除操作后表空间中将会有大量的空隙,特别是对于统计分析,日志系统这类应用最不适合用共享表空间。

2、事务
1)MyISAM
不支持事务。强调性能,执行度比InnoDB类型快。

2)InnoDB
支持事务。提供外部键等高级数据库功能。
InnoDB的AUTOCOMMIT默认是打开的,即每条SQL语句会默认被封装成一个事务,自动提交,不过这样会影响效率;我们可以合并事务,把多条SQL语句显示放在begin和commit之间,组成一个事务再提交,减少数据库多次提交导致的开销,提高性能。

3、CURD操作
1)MyISAM

  • 如果执行大量的select,MyISAM是最好的选择。

2)InnoDB

  • 如果执行大量的INSERT或UPDATE,从性能方面考虑应该使用InnoDB;
  • 执行 delete from table,InnoDB不会重新建立表,而是一行一行的删除;
  • load table from master 操作对InnoDB是不起作用的,解决方法:把InnoDB变成MyISAM表,导入数据后再改成InnoDB。不过对于使用额外的InnoDB特性(外键)的表不适用。

4、AUTO_INCREMENT
1)MyISAM

  • MyISAM为INSERT和UPDATE操作自动更新这一列,使得AUTO_INCREMENT列更快。在序列顶的值被删除之后就不能再利用。(当AUTO_INCREMENT列被定义为多列索引的最后一列,可以出现重使用从序列顶部删除的值的情况)
  • AUTO_INCREMENT值可用ALTER TABLE或myisamch来重置。
  • 对于AUTO_INCREMENT类型的字段可以和其他字段一起建立联合索引。

2)InnoDB

  • 如果你为一个表指定AUTO_INCREMENT列,在数据词典里的InnoDB表句柄包含一个名为自动增长计数器的计数器,它被用在为该列赋新值。
  • 自动增长计数器仅被存储在主内存中,而不是存在磁盘上。

5、表行
1)MyISAM
MyISAM保存表的具体行数,在查询语句 select count(*) from table查询表的总行数时,只需要简单读出保存的行数。
不过,当count(*)语句包含where条件时,需要扫描整个表来获取行数。

2)InnoDB
InnoDB 中不保存表的具体行数,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行。

6、锁
表级锁:- 当插入表的时候,表级锁锁住了整张表。
- 开销小,加锁快,不会出现死锁,锁粒度大(整张表),并发度低,发生锁竞争概率大。
行级锁:- 对于一条数据更改多个属性,使用行级锁。
- 开销大,加锁慢,会出现死锁,锁粒度最小(一行数据),并发度高,发生锁竞争概率小。
页级锁:- 数据在磁盘是一页一页存储,一页是4K,对于一个比较大的表(如几千万)时,这时对表的一部分数据加锁,一页只允许一个操作。
- 开销、加锁速度、锁粒度、并发度都介于表级锁和行级锁之间,会出现死锁。

1)MyISAM
提供表锁。

2)InnoDB
提供行锁、表锁。

行锁是通过给索引项加锁来实现的,在以下情况会失效,锁的是整表:

  • 不是通过索引条件检索数据,如update table set a=1 where user like '%lee%'
  • DELETE FROM mytable这样的删除语句。

7、表主键
1)MyISAM
允许没有任何索引和主键的表存在,索引都是保存行的地址。

2)InnoDB
对于主键索引,即存储索引值(主键的值),也存储每列的数据。如果没有设置主键,那么会尝试将外键作为主键。如果也没有外键,那么会自动生成一个隐藏的ROWID做主键。InnoDB的主键范围更大,最大是MyISAM的2倍。

8、全文索引
1)MyISAM
支持(FULLTEXT类型)全文索引。

2)InnoDB
不支持(FULLTEXT类型)全文索引,不过可以使用sphinx插件支持全文索引,并且效果更好。

问:为什么InnoDB本身不支持全文索引?
InnoDB数据已经在节点上了,如果要全文索引,相当于复制了一个数据库。

问:博客系统文章应该采用哪个存储引擎?
博客系统的文章存储在MyISAM中比较好存储,InnoDB的叶子节点用来存储文章使得叶子节点太大,不适合用于存储文章。博客系统的全文索引是做了一个摘要,做了MD5值,从而进行查询。

问:数据查找哪个比较快?
对于一张表而言,MyISAM可以把整张表的索引树全部加入到内存中,然后到磁盘中找。而InnoDB是把一部分数据加入到内存中,因为它可以直接拿到数据。
查找一条数据(数据较少)的话,MyISAM比InnoDB快,而查询数据比较多的时候InnoDB比MyISAM快,这是因为MyISAM每读取一条数据都要读取一次磁盘,而InnoDB可以把常用的这部分数据存储在内存中。

2、使用场景

1)MyISAM

  • 读操作业务为主,且UPDATE相对较少,适合使用MyISAM。
  • 并发不高。
  • 表数据量小。
  • 硬件资源有限。

2)InnoDB

  • 读写量不多,频繁更新大字段, 选择InnoDB。
  • 表数据量超过1000万,并发高。
  • 安全性和可靠性要求高。

猜你喜欢

转载自blog.csdn.net/locahuang/article/details/110475389