第 3 章 MySQL 存储引擎简介
3.1MySQL 存储引擎概述
到后来,MySQL 意识到需要更改架构,将前端的业务逻辑和后端数据存储以
清晰的层次结构拆分开的同时,对ISAM 做了功能上面的扩展和代码的重构,这就是MyISAM
存储引擎的由来。
MySQL 的插件式存储引擎主要包括MyISAM,Innodb,NDB Cluster,Maria,Falcon,
Memory,Archive,Merge,Federated 等,其中最著名而且使用最为广泛的MyISAM 和Innodb
两种存储引擎。MyISAM 是MySQL 最早的ISAM 存储引擎的升级版本,也是MySQL 默认的存储
引擎。而Innodb 实际上并不是MySQ 公司的,而是第三方软件公司Innobase(在2005 年
被Oracle 公司所收购)所开发,其最大的特点是提供了事务控制等特性, 所以使用者也非
常广泛。
其他的一些存储引擎相对来说使用场景要稍微少一些,都是应用于某些特定的场景,如
NDB Cluster 虽然也支持事务,但是主要是用于分布式环境,属于一个share nothing 的分
布式数据库存储引擎。Maria 是MySQL 最新开发(还没有发布最终的GA 版本)的对MyISAM
的升级版存储引擎,Falcon 是MySQL 公司自行研发的为了替代当前的Innodb 存储引擎的一
款带有事务等高级特性的数据库存储引擎,目前正在研发阶段。Memory 存储引擎所有数据
和索引均存储于内存中,所以主要是用于一些临时表,或者对性能要求极高,但是允许在西
噢他嗯Crash 的时候丢失数据的特定场景下。Archive 是一个数据经过高比例压缩存放的
存储引擎,主要用于存放过期而且很少访问的历史信息,不支持索引。Merge 和Federated
在严格意义上来说,并不能算作一个存储引擎。因为Merge 存储引擎主要用于将几个基表
merge 到一起,对外作为一个表来提供服务,基表可以基于其他的几个存储引擎。而
Federated 实际上所做的事情,有点类似于Oracle 的dblink,主要用于远程存取其他MySQL
服务器上面的数据。
3.2MyISAM 存储引擎简介
MyISAM 存储引擎的表在数据库中,每一个表都被存放为三个以表名命名的物理文件。
首先肯定会有任何存储引擎都不可缺少的存放表结构定义信息的.frm 文件,另外还有.MYD
和.MYI 文件,分别存放了表的数据(.MYD)和索引数据(.MYI)。每个表都有且仅有这样三
个文件做为MyISAM 存储类型的表的存储,也就是说不管这个表有多少个索引,都是存放在
同一个.MYI 文件中。
1、B-Tree 索引
B-Tree 索引,顾名思义,就是所有的索引节点都按照balance tree 的数据结构来
存储,所有的索引数据节点都在叶节点。
2、R-Tree 索引
R-Tree 索引的存储方式和b-tree 索引有一些区别,主要设计用于为存储空间和多
维数据的字段做索引,所以目前的MySQL 版本来说,也仅支持geometry 类型的字段作索引。
3、Full-text 索引
Full-text 索引就是我们长说的全文索引,他的存储结构也是b-tree。主要是为了
解决在我们需要用like 查询的低效问题。
MyISAM 上面三种索引类型中,最经常使用的就是B-Tree 索引了,偶尔会使用到Fulltext,
但是R-Tree 索引一般系统中都是很少用到的。另外MyISAM 的B-Tree 索引有一个较
大的限制,那就是参与一个索引的所有字段的长度之和不能超过1000 字节。
虽然每一个MyISAM 的表都是存放在一个相同后缀名的.MYD 文件中,但是每个文件的存
放格式实际上可能并不是完全一样的,因为MyISAM 的数据存放格式是分为静态(FIXED)固
定长度、动态(DYNAMIC)可变长度以及压缩(COMPRESSED)这三种格式。当然三种格式中
是否压缩是完全可以任由我们自己选择的,可以在创建表的时候通过ROW_FORMAT 来指定
{COMPRESSED | DEFAULT},也可以通过myisampack 工具来进行压缩,默认是不压缩的。而
在非压缩的情况下,是静态还是动态,就和我们表中个字段的定义相关了。只要表中有可变
长度类型的字段存在,那么该表就肯定是DYNAMIC 格式的,如果没有任何可变长度的字段,
则为FIXED 格式,当然,你也可以通过alter table 命令,强行将一个带有VARCHAR 类型字
段的DYNAMIC 的表转换为FIXED,但是所带来的结果是原VARCHAR 字段类型会被自动转换成
CHAR 类型。相反如果将FIXED 转换为DYNAMIC,也会将CHAR 类型字段转换为VARCHAR 类型,
所以大家手工强行转换的操作一定要谨慎。
MyISAM 存储引擎的表是否足够可靠呢?在MySQL 用户参考手册中列出在遇到如下情况
的时候可能会出现表文件损坏:
1、当mysqld 正在做写操作的时候被kill 掉或者其他情况造成异常终止;
2、主机Crash;
3、磁盘硬件故障;
4、MyISAM 存储引擎中的bug?
MyISAM 存储引擎的某个表文件出错之后,仅影响到该表,而不会影响到其他表,更不
会影响到其他的数据库。如果我们的出据苦正在运行过程中发现某个MyISAM 表出现问题了,
则可以在线通过check table 命令来尝试校验他,并可以通过repair table 命令来尝试修
复。在数据库关闭状态下,我们也可以通过myisamchk 工具来对数据库中某个(或某些)表
进行检测或者修复。不过强烈建议不到万不得已不要轻易对表进行修复操作,修复之前尽量
做好可能的备份工作,以免带来不必要的后果。
另外MyISAM 存储引擎的表理论上是可以被多个数据库实例同时使用同时操作的,但是
不论是我们都不建议这样做,而且MySQL 官方的用户手册中也有提到,建议尽量不要在多个
mysqld 之间共享MyISAM 存储文件。
3.3 Innodb 存储引擎简介
在MySQL 中使用最为广泛的除了MyISAM 之外,就非Innodb 莫属了。Innodb 做为第三
方公司所开发的存储引擎,和MySQL 遵守相同的开源License 协议。
Innodb 之所以能如此受宠,主要是在于其功能方面的较多特点:
1、支持事务安装
Innodb 在功能方面最重要的一点就是对事务安全的支持,这无疑是让Innodb 成为MySQL
最为流行的存储引擎之一的一个非常重要原因。而且实现了SQL92 标准所定义的所有四个级
别(READ UNCOMMITTED,READ COMMITTED,REPEATABLE READ 和SERIALIZABLE)。对事务安
全的支持,无疑让很多之前因为特殊业务要求而不得不放弃使用MySQL 的用户转向支持
MySQL,以及之前对数据库选型持观望态度的用户,也大大增加了对MySQL 好感。
2、数据多版本读取
Innodb 在事务支持的同时,为了保证数据的一致性已经并发时候的性能,通过对undo
信息,实现了数据的多版本读取。
3、锁定机制的改进
Innodb 改变了MyISAM 的锁机制,实现了行锁。虽然Innodb 的行锁机制的实现是通过
索引来完成的,但毕竟在数据库中99%的SQL 语句都是要使用索引来做检索数据的。所以,
行锁定机制也无疑为Innodb 在承受高并发压力的环境下增强了不小的竞争力。
4、实现外键
Innodb 实现了外键引用这一数据库的重要特性,使在数据库端控制部分数据的完整性
成为可能。虽然很多数据库系统调优专家都建议不要这样做,但是对于不少用户来说在数据
库端加如外键控制可能仍然是成本最低的选择。
除了以上几个功能上面的亮点之外,Innodb 还有很多其他一些功能特色常常带给使用
者不小的惊喜,同时也为MySQL 带来了更多的客户。
在物理存储方卖弄,Innodb 存储引擎也和MyISAM 不太一样,虽然也有.frm 文件来存放
表结构定义相关的元数据,但是表数据和索引数据是存放在一起的。至于是每个表单独存放
还是所有表存放在一起,完全由用户来决定(通过特定配置),同时还支持符号链接。
Innodb 的物理结构分为两大部分:
1、数据文件(表数据和索引数据)
存放数据表中的数据和所有的索引数据,包括主键和其他普通索引。在Innodb 中,存
在了表空间(tablespace)这样一个概念,但是他和Oracle 的表空间又有较大的不同。首
先,Innodb 的表空间分为两种形式。一种是共享表空间,也就是所有表和索引数据被存放
在同一个表空间(一个或多个数据文件)中,通过innodb_data_file_path 来指定,增加数
据文件需要停机重启。另外一种是独享表空间,也就是每个表的数据和索引被存放在一个
单独的.ibd 文件中。
虽然我们可以自行设定使用共享表空间还是独享表空间来存放我们的表,但是共享表空
间都是必须存在的,因为Innodb 的undo 信息和其他一些元数据信息都是存放在共享表空间
里面的。共享表空间的数据文件是可以设置为固定大小和可自动扩展大小两种形式的,自动
扩展形式的文件可以设置文件的最大大小和每次扩展量。在创建自动扩展的数据文件的时
候,建议大家最好加上最大尺寸的属性,一个原因是文件系统本身是有一定大小限制的(但
是Innodb 并不知道),还有一个原因就是自身维护的方便。另外,Innodb 不仅可以使用文
件系统,还可以使用原始块设备,也就是我们常说的裸设备。
当我们的文件表空间快要用完的时候,我们必须要为其增加数据文件,当然,只有共享
表空间有此操作。共享表空间增加数据文件的操作比较简单, 只需要在
innodb_data_file_path 参数后面按照标准格式设置好文件路径和相关属性即可,不过这里
有一点需要注意的,就是Innodb 在创建新数据文件的时候是不会创建目录的,如果指定目
录不存在,则会报错并无法启动。另外一个较为令人头疼的就是Innodb 在给共享表空间增
加数据文件之后,必须要重启数据库系统才能生效,如果是使用裸设备,还需要有两次重启。
这也是我一直不太喜欢使用共享表空间而选用独享表空间的原因之一。
2、日志文件
Innodb 的日志文件和Oracle 的redo 日志比较类似,同样可以设置多个日志组(最少2
个),同样采用轮循策略来顺序的写入,甚至在老版本中还有和Oracle 一样的日志归档特性。
如果你的数据库中有创建了Innodb 的表,那么千万别全部删除innodb 的日志文件,因为很
可能就会让你的数据库crash,无法启动,或者是丢失数据。
由于Innodb 是事务安全的存储引擎,所以系统Crash 对他来说并不能造成非常严重的
损失,由于有redo 日志的存在,有checkpoint 机制的保护,Innodb 完全可以通过redo 日
志将数据库Crash 时刻已经完成但还没有来得及将数据写入磁盘的事务恢复,也能够将所有
部分完成并已经写入磁盘的未完成事务回滚并将数据还原。
Innodb 不仅在功能特性方面和MyISAM 存储引擎有较大区别,在配置上面也是单独处理
的。在MySQL 启动参数文件设置中,Innodb 的所有参数基本上都带有前缀“innodb_”,不
论是innodb 数据和日志相关,还是其他一些性能,事务等等相关的参数都是一样。和所有
Innodb 相关的系统变量一样,所有的Innodb 相关的系统状态值也同样全部以“Innodb_”
前缀。当然,我们也完全可以仅仅通过一个参数(skip-innodb)来屏蔽MySQL 中的Innodb
存储引擎,这样即使我们在安装编译的时候将Innodb 存储引擎安装进去了,使用者也无法
创建Innodb 的表。
3.4 NDB Cluster 存储引擎简介
NDB 存储引擎也叫NDB Cluster 存储引擎,主要用于MySQL Cluster 分布式集群环境,
Cluster 是MySQL 从5.0 版本才开始提供的新功能。这部分我们可能并不仅仅只是介绍NDB
存储引擎,因为离开了MySQL CLuster 整个环境,NDB 存储引擎也将失去太多意义。所以
这一节主要是介绍一下MySQL Cluster 的相关内容。
简单的说,Mysql Cluster 实际上就是在无共享存储设备的情况下实现的一种内存数据
库Cluster 环境,其主要是通过NDB Cluster(简称NDB)存储引擎来实现的。
一般来说,一个Mysql Cluster 的环境主要由以下三部分组成:
a) 负责管理各个节点的Manage 节点主机:
管理节点负责整个Cluster 集群中各个节点的管理工作,包括集群的配置,启动关闭
各节点,以及实施数据的备份恢复等。管理节点会获取整个Cluster 环境中各节点的状态和
错误信息,并且将各Cluster 集群中各个节点的信息反馈给整个集群中其他的所有节点。由
于管理节点上保存在整个Cluster 环境的配置,同时担任了集群中各节点的基本沟通工作,
所以他必须是最先被启动的节点。
b) SQL 层的SQL 服务器节点(后面简称为SQL 节点),也就是我们常说的Mysql Server:
主要负责实现一个数据库在存储层之上的所有事情,比如连接管理,query 优化和响
应,cache 管理等等,只有存储层的工作交给了NDB 数据节点去处理了。也就是说,在纯粹
的Mysql Cluster 环境中的SQL 节点,可以被认为是一个不需要提供任何存储引擎的Mysql
服务器,因为他的存储引擎有Cluster 环境中的NDB 节点来担任。所以,SQL 层各Mysql 服
务器的启动与普通的Mysql 启动有一定的区别,必须要添加ndbcluster 项,可以添加在
my.cnf 配置文件中,也可以通过启动命令行来指定。
c) Storage 层的NDB 数据节点,也就是上面说的NDB Cluster:
NDB 是一个内存式存储引擎也就是说,他会将所有的数据和索引数据都load 到内存中,
但也会将数据持久化到存储设备上。不过,最新版本,已经支持用户自己选择数据可以不全
部Load 到内存中了,这对于有些数据量太大或者基于成本考虑而没有足够内存空间来存放
所有数据的用户来说的确是一个大好消息。
NDB 节点主要是实现底层数据存储的功能,保存Cluster 的数据。每一个NDB 节点保存
完整数据的一部分(或者一份完整的数据,视节点数目和配置而定),在MySQL CLuster 里
面叫做一个fragment。而每一个fragment,正常情况来讲都会在其他的主机上面有一份(或
者多分)完全相同的镜像存在。这些都是通过配置来完成的,所以只要配置得当,Mysql
Cluster 在存储层不会出现单点的问题。一般来说,NDB 节点被组织成一个一个的NDB Group,
一个NDB Group 实际上就是一组存有完全相同的物理数据的NDB 节点群。
上面提到了NDB 各个节点对数据的组织,可能每个节点都存有全部的数据也可能只保存
一部分数据,主要是受节点数目和参数来控制的。首先在Mysql Cluster 主配置文件(在管
理节点上面,一般为config.ini)中,有一个非常重要的参数叫NoOfReplicas,这个参数
指定了每一份数据被冗余存储在不同节点上面的份数,该参数一般至少应该被设置成2,也
只需要设置成2 就可以了。因为正常来说,两个互为冗余的节点同时出现故障的概率还是非
常小的,当然如果机器和内存足够多的话,也可以继续增大。一个节点上面是保存所有的数
据还是一部分数据,还受到存储节点数目的限制。NDB 存储引擎首先保证NoOfReplicas 参
数配置的要求对数据冗余,来使用存储节点,然后再根据节点数目将数据分段来继续使用多
余的NDB 节点,分段的数目为节点总数除以NoOfReplicas 所得。
MySQL Cluster 本身所包含的内容非常之多,出于篇幅考虑,这里暂时不做很深入的介
绍,在本书的架构设计部分的高可用性设计一章中将会有更为详细的介绍与实施细节,大家
也可以通过MySQL 官方文档来进一步了解部分细节。
3.5 其他存储引擎介绍
3.5.1 Merge存储引擎:
MERGE 存储引擎,在MySQL 用户手册中也提到了,也被大家认识为MRG_MyISAM 引擎。
Why?因为MERGE 存储引擎可以简单的理解为其功能就是实现了对结构相同的MyISAM 表,通
过一些特殊的包装对外提供一个单一的访问入口,以达到减小应用的复杂度的目的。要创建
MERGE 表,不仅仅基表的结构要完全一致,包括字段的顺序,基表的索引也必须完全一致。
MERGE 表本身并不存储数据,仅仅只是为多个基表提供一个同意的存储入口。所以在创
建MERGE 表的时候,MySQL 只会生成两个较小的文件,一个是.frm 的结构定义文件,还有一
个.MRG 文件,用于存放参与MERGE 的表的名称(包括所属数据库schema)。之所以需要有所
属数据库的schema,是因为MERGE 表不仅可以实现将Merge 同一个数据库中的表,还可以
Merge 不同数据库中的表,只要是权限允许,并且在同一个mysqld 下面,就可以进行Merge。
MERGE 表在被创建之后,仍然可以通过相关命令来更改底层的基表。
MERGE 表不仅可以提供读取服务,也可以提供写入服务。要让MERGE 表提供可INSERT
服务,必须在在表被创建的时候就指明INSERT 数据要被写入哪一个基表,可以通过
insert_method 参数来控制。如果没有指定该参数,任何尝试往MERGE 表中INSERT 数据的
操作,都会出错。此外,无法通过MERGE 表直接使用基表上面的全文索引,要使用全文索引,
必须通过基表本身的存取才能实现。
3.5.2 Memory存储引擎:
Memory 存储引擎,通过名字就很容易让人知道,他是一个将数据存储在内存中的存储
引擎。Memory 存储引擎不会将任何数据存放到磁盘上,仅仅存放了一个表结构相关信息
的.frm 文件在磁盘上面。所以一旦MySQL Crash 或者主机Crash 之后,Memory 的表就只剩
下一个结构了。Memory 表支持索引,并且同时支持Hash 和B-Tree 两种格式的索引。由于
是存放在内存中,所以Memory 都是按照定长的空间来存储数据的,而且不支持BLOB 和TEXT
类型的字段。Memory 存储引擎实现页级锁定。
既然所有数据都存放在内存中,那么他对内存的消耗量是可想而知的。在MySQL 的用户
手册上面有这样一个公式来计算Memory 表实际需要消耗的内存大小:
SUM_OVER_ALL_BTREE_KEYS(max_length_of_key + sizeof(char*) * 4)
+ SUM_OVER_ALL_HASH_KEYS(sizeof(char*) * 2)
+ ALIGN(length_of_row+1, sizeof(char*))
3.5.3 BDB 存储引擎
BDB 存储引擎全称为BerkeleyDB 存储引擎,和Innodb 一样,也不是MySQL 自己开发实
现的一个存储引擎,而是由Sleepycat Software 所提供,当然,也是开源存储引擎,同样
支持事务安全。
BDB 存储引擎的数据存放也是每个表两个物理文件,一个.frm 和一个.db 的文件,数据
和索引信息都是存放在.db 文件中。此外,BDB 为了实现事务安全,也有自己的redo 日志,
和Innodb 一样,也可以通过参数指定日志文件存放的位置。在锁定机制方面,BDB 和Memory
存储引擎一样,实现页级锁定。
由于BDB 存储引擎实现了事务安全,那么他肯定也需要有自己的check point 机制。BDB
在每次启动的时候,都会做一次check point,并且将之前的所有redo 日志清空。在运行
过程中,我们也可以通过执行flush logs 来手工对BDB 进行check point 操作。
3.5.4 FEDERATED存储引擎:
FEDERATED 存储引擎所实现的功能,和Oracle 的DBLINK 基本相似,主要用来提供对远
程MySQL 服务器上面的数据的访问借口。如果我们使用源码编译来安装MySQL,那么必须手
工指定启用
FEDERATED 存储引擎才行,因为MySQL 默认是不起用该存储引擎的。
当我们创建一个FEDERATED 表的时候,仅仅在本地创建了一个表的结构定义信息的文件
而已,所有数据均实时取自远程的MySQL 服务器上面的数据库。
当我们通过SQL 操作FEDERATED 表的时候,实现过程基本如下:
a、SQL 调用被本地发布
b、MySQL 处理器API(数据以处理器格式)
c、MySQL 客户端API(数据被转换成SQL 调用)
d、远程数据库-> MySQL 客户端API
e、转换结果包(如果有的话)到处理器格式
f、处理器API -> 结果行或受行影响的对本地的计数
3.5.5 ARCHIVE存储引擎:
ARCHIVE 存储引擎主要用于通过较小的存储空间来存放过期的很少访问的历史数据。
ARCHIVE 表不支持索引,通过一个.frm 的结构定义文件,一个.ARZ 的数据压缩文件还有一
个.ARM 的meta 信息文件。由于其所存放的数据的特殊性,ARCHIVE 表不支持删除,修改操
作,仅支持插入和查询操作。锁定机制为行级锁定。
3.5.6 BLACKHOLE存储引擎:
BLACKHOLE 存储引擎是一个非常有意思的存储引擎,功能恰如其名,就是一个“黑洞”。
就像我们unix 系统下面的“/dev/null”设备一样,不管我们写入任何信息,都是有去无回。
那么BLACKHOLE存储引擎对我们有什么用呢?在我最初接触MySQL 的时候我也有过同样的疑
问,不知道MySQL 提供这样一个存储引擎给我们的用意为何?但是后来在又一次数据的迁移
过程中,正是BLACKHOLE 给我带来了非常大的功效。在那次数据迁移过程中,由于数据需要
经过一个中转的MySQL 服务器做一些相关的转换操作,然后再通过复制移植到新的服务器上
面。可当时我没有足够的空间来支持这个中转服务器的运作。这时候就显示出BLACKHOLE
的功效了,他不会记录下任何数据,但是会在binlog 中记录下所有的sql。而这些sql 最
终都是会被复制所利用,并实施到最终的slave 端。
MySQL 的用户手册上面还介绍了BLACKHOLE 存储引擎其他几个用途如下:
a、SQL 文件语法的验证。
b、来自二进制日志记录的开销测量,通过比较允许二进制日志功能的BLACKHOLE 的性
能与禁止二进制日志功能的BLACKHOLE 的性能。
c、因为BLACKHOLE 本质上是一个“no-op” 存储引擎,它可能被用来查找与存储引擎
自身不相关的性能瓶颈。
3.5.7 CSV存储引擎:
CSV 存储引擎实际上操作的就是一个标准的CSV 文件,他不支持索引。起主要用途就是
大家有些时候可能会需要通过数据库中的数据导出成一份报表文件,而CSV 文件是很多软件
都支持的一种较为标准的格式,所以我们可以通过先在数据库中建立一张CVS 表,然后将生
成的报表信息插入到该表,即可得到一份CSV 报表文件了。