MySQL由以下几部分组成:

  • 连接池组件
  • 管理服务和工具组件
  • SQL接口组件
  • 查询分析器组件
  • 优化器组件
  • 缓冲(Cache)组件
  • 插件式存储引擎
  • 物理文件

MySQL区别于其他数据库的最重要的特点就是其插件式的表存储引擎。MySQL插件式的存储引擎架构提供了一系列标准的管理和服务支持,这些标准与存储引擎本身无关,可能是每个数据库系统本身都必需的,如SQL分析器和优化器等,而存储引擎是底层物理结构的实现,每个存储引擎开发者都可以按照自己的意愿来进行开发。

注意:存储引擎是基于表的,而不是数据库。

MySQL常用的插件式存储引擎主要包括MyISAM,InnoDB,NDB Cluster,Maria,Falcon,Memory,Archive,Merge,Federated等,其中最著名且使用最广泛的是MyISAM和InnoDB。MyISAM是MySQL的默认存储引擎,是MySQL最早的ISAM存储引擎的升级版本。

MyISAM存储引擎

MyISAM是MySQL的默认存储引擎,它支持B-tree/FullText/R-tree索引类型。
MyISAM的锁级别是表锁,表锁的开销小,加锁快;锁粒度大,发生锁冲突的概率较高,并发度低;表锁适合查询。MyISAM引擎不支持事务性,也不支持外键。

MyISAM对于一些OLAP(Online Analytical Processing,在线分析处理)操作速度快。除Windows版本外,是所有MySQL版本默认的存储引擎。

MyISAM存储引擎表由MYD和MYI组成,MYD用来存放数据文件,MYI用来存放索引文件。可以通过使用myisampack工具来进一步压缩数据文件,因为myisampack工具使用赫夫曼(Huffman)编码静态算法来压缩数据,因此使用myisampack工具压缩后的表是只读的,当然你也可以通过myisampack来解压数据文件

在MySQL 5.0版本之前,MyISAM默认支持的表大小为4G,如果需要支持大于4G的MyISAM表时,则需要制定MAXROWS和 AVGROW_LENGTH属性。从MySQL 5.0版本开始,MyISAM默认支持256T的单表数据,这足够满足一般应用的需求。

注意:对于MyISAM存储引擎表,MySQL数据库只缓存其索引文件,数据文件的缓存交由操作系统本身来完成,这与其他使用LRU算法缓存数据 的大部分数据库大不相同。此外,在MySQL 5.1.23版本之前,无论是在32位还是64位操作系统环境下,缓存索引的缓冲区最大只能设置为4G。在之后的版本中,64位系统可以支持大于4G的索引缓冲区。

InnoDB存储引擎

InnoDB存储引擎最大的亮点就是支持事务性,支持回滚。它支持Hash/B-tree索引类型。
InnoDB的锁级别是行锁,行锁在锁定上带来的消耗大于表锁,但是在系统并发访问量较高时,InnoDB整体性能远高于MyISAM。InnoDB的索引不仅缓存索引本身,也缓存数据,所以InnoDB需要更大的内存。

InnoDB存储引擎支持事务,主要面向在线事务处理(OLTP)方面的应用。其特点是行锁设计、支持外键,并支持类似于Oracle的非锁定读,即默认情况下读取操作不会产生锁。MySQL在Windows版本下的InnoDB是默认的存储引擎,同时InnoDB默认地被包含在所有的MySQL二进制发布版本中。

InnoDB存储引擎将数据放在一个逻辑的表空间中,这个表空间就像黑盒一样由InnoDB自身进行管理。从MySQL 4.1(包括4.1)版本开始,它可以将每个InnoDB存储引擎的表单独存放到一个独立的ibd文件中。与Oracle类似,InnoDB存储引擎同样可以使用裸设备(row disk)来建立其表空间。

InnoDB通过使用多版本并发控制(MVCC)来获得高并发性,并且实现了SQL标准的4种隔离级别,默认为REPEATABLE级别。同时使用一种被称为next-key locking 的策略来避免幻读(phantom)现象的产生。除此之外,InnoDB储存引擎还提供了插入缓冲(insert buffer)、二次写(double write)、自适应哈希索引(adaptive hash index)、预读(read ahead)等高性能和高可用的功能。

对于表中数据的存储,InnoDB存储引擎采用了聚簇(clustered)的方式,这种方式类似于Oracle的索引聚集表(index organized table,IOT)。

每张表的存储都按主键的顺序存放,如果没有显式地在表定义时指定主键,InnoDB存储引擎会为每一行生成一个6字节的 ROWID,并以此作为主键。

Memory存储引擎

Memory存储引擎是一个内存级的存储引擎,它将所有数据都存储在内存中,所以它能够存储的数据量是比较小的。而因为内存的特性,Memory存储引擎对于数据的一致性支持教差。Memory的锁级别和MyISAM一样,是表锁;并且不支持事务性。

Memory存储引擎(之前称为HEAP存储引擎)将表中的数据存放在内存中,如果数据库重启或发生崩溃,表中的数据都将消失。它非常适合用于存储临时数据的临时表,以及数据仓库中的纬度表。它默认使用哈希索引,而不是我们熟悉的B+树索引。

虽然Memory存储引擎速度非常快,但在使用上还是有一定的限制。比如,其只支持表锁,并发性能较差,并且不支持TEXT和BLOB列类型。最重要的是,存储变长字段(varchar)时是按照定常字段(char)的方式进行的,因此会浪费内存(这个问题之前已经提到,eBay的Igor Chernyshev工程师已经给出了Patch方案)。
此外有一点常被忽视的是,MySQL数据库使用Memory存储引擎作为临时表来存放查询的中间结果集(intermediate result)。如果中间结果集大于Memory存储引擎表的容量设置,又或者中间结果含有TEXT或BLOB列类型字段,则MySQL数据库会把其转换到MyISAM存储引擎表而存放到磁盘。之前提到MyISAM不缓存数据文件,因此这时产生的临时表的性能对于查询会有损失。

NDB存储引擎

2003年,MySQL AB公司从Sony Ericsson公司收购了NDB 集群引擎。NDB存储引擎是一个集群存储引擎,类似于Oracle的RAC集群;不过,与Oracle RAC share everything结构不同的是,其结构是share nothing的集群架构,因此能提供更高级别的高可用性。NDB的特点是数据全部放在内存中(从5.1版本开始,可以将非索引数据放在磁盘上),因此主键查找(primary key lookup)的速度极快,并且通过添加NDB数据存储节点(Data Node)可以线性地提高数据库性能,是高可用、高性能的集群系统。

关于NDB存储引擎,有一个问题值得注意,那就是NDB存储引擎的连接操作(JOIN)是在MySQL数据库层完成的,而不是在存储引擎层完成的。这意味着,复杂的连接操作需要巨大的网络开销,因此查询速度很慢。如果解决了这个问题,NDB存储引擎的市场应该是非常巨大的。

注意:MySQL NDB Cluster存储引擎有社区版本和企业版本,并且NDB Cluster已作为Carrier Grade Edition单独下载版本而存在,可以通过[http://dev.mysql.com/ downloads/cluster/index.html](http://dev.mysql.com/ downloads/cluster/index.html)获得最新版本的NDB Cluster存储引擎。

Archive存储引擎

Archive存储引擎只支持INSERT和SELECT操作,MySQL 5.1开始支持索引。其使用zlib算法将数据行(row)进行压缩后存储,压缩比率一般可达1∶10。正如其名称所示,Archive存储引擎非常适合存储归档数据,如日志信息。Archive存储引擎使用行锁来实现高并发的插入操作,但是本身并不是事物安全的存储引擎,其设计目标主要是提供高速的插入 和压缩功能。

Federated存储引擎

Federated存储引擎表并不存放数据,它只是指向一台远程MySQL数据库服务器上的表。这非常类似于SQL Server的链接服务器和Oracle的透明网关,不同的是,当前Federated存储引擎只支持MySQL数据库表,不支持异构数据库表。

Maria存储引擎

Maria存储引擎是新开发的引擎,设计目标主要是用来取代原有的MyISAM存储引擎,从而成为MySQL的默认存储引擎,开发者是MySQL 的创始人之一的Michael Widenius。因此,它可以看作是MyISAM的后续版本。其特点是:缓存数据和索引文件,行锁设计,提供MVCC功能,支持事务和非事务安全的选项 支持,以及更好的BLOB字符类型的处理性能。

其他存储引擎

除了上面提到的7种存储引擎外,还有很多其他的存储引擎,包括Merge、CSV、Sphinx和Infobright,它们都有各自适用的场合,这里不再一一做介绍了。了解了MySQL拥有这么多存储引擎后,现在我可以回答1.2节中提到的问题了。

为什么MySQL不支持全文索引?不!MySQL支持,MyISAM、Sphinx存储引擎支持全文索引。
MySQL快是因为不支持事务吗?错!MySQL MyISAM存储引擎不支持事务,但是InnoDB支持。快是相对于不同应用来说的,对于ETL这种操作,MyISAM当然有其优势。
当表的数据量大于1000W时,MySQL的性能会急剧下降吗?不!MySQL是数据库,不是文件,随着数据行数的增加,性能当然会有所下降,但是这些下降不是线性的,如果 你选择了正确的存储引擎以及正确的配置,再大的数据量MySQL也是能承受的。如官方手册上提及的,Mytrix和Inc.在InnoDB上存储了超过 1TB的数据,还有一些其他网站使用InnoDB存储引擎处理平均每秒800次插入/更新的操作。

MyISAM和InnoDB差别

构成差别

每个MyISAM在磁盘上存储成三个文件,文件的名字以表的名字开始,.frm文件存储表定义,.MYI(MYIndex)为索引文件,.MYD(MYData)为数据文件。

基于磁盘的资源是InnoDB表空间数据文件和它的日志文件,InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。

事务处理差别

MyISAM类型的表强调性能,执行速度比InnoDB快,但是不支持事务处理等高级功能。

InnoDB提供事务支持、外部键等高级数据库功能。

CRUD操作

如果执行大量SELECT查询操作,MyISAM是最好的选择。

如果执行大量的UPDATE或者INSERT操作,出于性能方面考虑,应该使用InnoDB。DELETE from table时,InnoDB不会重新建立表,而是一行一行的删除。
LOAD TABLE FROM MASTER操作对InnoDB不起作用,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。

AUTO_INCREMENT操作

MyISAM为INSERT和UPDATE操作自动更新这一列,这使得AUTO_INCREMENT列更快(10%+),在序列项的值删除后就不能再利用。(当AUTO_INCREMENT列被定义为多列索引的最后一列,可以出现重使用从序列顶部删除的值的情况)。
AUTO_INCREMENT值可用ALTER TABLE或myisamch来重置。

对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但 是在MyISAM表中,可以和其他字段一起建立联合索引。
如果你为一个表指定AUTO_INCREMENT列,在数据词典里的InnoDB表句柄包含一个名为自动增长计数器的计数器,它被用在为该列赋新值。InnoDB自动增长计数器仅被存储在主内存中,而不是存在磁盘上。

表的具体行数

select count(*) from table,MyISAM只要简单的读出保存好的行数。注意的是,当count(*)语句包含 where 条件时,两种类型表的操作是一样的。

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

MyISAM的锁是在表级别。其并发写的性能一直是一个让人比较头疼的问题。

InnoDB提供了行级别的锁(locking on row level),提供与 Oracle类型一致的不加锁读取(non-locking read in SELECTs)。另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like '%aaa%'

索引

MyISAM的索引和数据是分开的,并且索引是有压缩的,内存使用率就对应提高了不少。能加载更多索引。

Innodb是索引和数据是存放在相同的文件,没有使用压缩从而会造成Innodb比MyISAM体积庞大不小。Innodb 的数据存放格式也比较独特,每个Innodb表 都会将主键以聚簇索引的形式创建。所有的数据都是以主键来作为升序排列在物理磁盘上面,所以主键 查询并且以主键排序的查询效率也会非常高。

如何选择合适的引擎

采用MyISAM引擎

R/W > 100 ,并且Update较少 (R/W:读写比)
并发不高,不需要支持事务
表数据量小
需要进行全文搜索

采用InnoDB引擎

R/W比较小,频繁更新大字段
表数据量超过千万,高并发
安全性和可用性要求高

采用Memory引擎

有足够的内存
对数据一致性要求不高,如session/在线人数等
需要定期归档的数据

参考资料