首页 > 数据库 >MySQL的架构与历史1.5MySQL的存储引擎

MySQL的架构与历史1.5MySQL的存储引擎

时间:2022-12-02 11:58:35浏览次数:29  
标签:1.5 存储 架构 索引 引擎 InnoDB MyISAM MySQL

1.5 MySQL的存储引擎

1.5.1 InnoDB存储引擎

InnoDB是 MySQL的默认事务型引,也是最重要、使用最广泛的存储引擎。它被设计用来处理大量的短期 (short-lived)事务,短期事务大部分情况是正常提交的,很少会被回滚。InnoDB 的性能和自动崩恢复特性,使得它在非事务型存储的需求中也很流行。除非有非常特别的原因需要使用其他的存储引擎,否则应该优先考虑 InnoDB 引擎如果要学习存储引擎,InnoDB 也是一个非常好的值得花最多的时间去深入学习的对象收益肯定比将时间平均花在每个存储引擎的学习上要高得多。

InnoDB的历史
InnoDB 有着复杂的发布历史,了解一下这段历对于理解InnoDB很有帮助。2008年发布了所谓的InnoDB plugin,适用于MySQL 5.1版本,但这是 Oracle 创建的下一代InnoDB引擎,其拥有者是InnoDB 而不是MySQL。这基于很多原因,这些原因如果要一一道来,恐怕得喝掉好几桶啤酒。MySQL 默认还是选择了集成旧的 InnoDB 引擎。当然用户可以自行选择使用新的性能更好、扩展性更佳的 InnoDB plugin 来盖的版本直到最后,在 Oracle 收购了 Sun 公司后发布的 MySQL 5.5中才彻底使用InnoDB plugin替代了旧版本的InnoDB (是的,这也意味着InoDB plugin 已经是原生编译了,而不是编译成一个插件,但名字已经约定俗成很难更改)。
这个现代的InnoDB 版本也就是 MySQL5.1中所谓的InnoDB plugin,支持一些新特性诸如利用排序创建索引 (building index by sorting)、删除或者增加索引时不需要复制全表数据、新的支持压缩的存储格式、新的大型列值如 BLOB 的存储方式,以及文件格式管理等。很多用户在 MySQL5.1中没有使用InnoDB plugin,或许是因为他们没有注意到有这个区别。所以如果你使用的是 MySQL 5.1,一定要使用InnoDB plugin,真的比旧版本的InnoDB要好很多。
InnoDB 是一个很重要的存储引擎,很多个人和公司都对其贡献代码,而不仅仅是Oracle 公司的开发团队。一些重要的贡献者包括 Google、Yasufumi Kinoshita、PerconaFacebook等他们的一些改进被直接移植到官方版本也有一些由 InnoDB 团队重新实现在过去的几年间,InnoDB 的改进速度大大加快主要的改进集中在可测量性可扩展性可配置化、性能、各种新特性和对 Windows 的支持等方面。MySQL 5.6 实验室预览版和里程碑版也包含了一系列重要的InnoDB新特性。
为改善 InnoDB 的性能,Oracle 投入了大量的资源,并做了很多卓有成效的工作(外部贡献者对此也提供了很大的帮助)。在本书的第二版中,我们注意到在超过四核CPU的系统中InnoDB 表现不佳,而现在已经可以很好地扩展至24 核的系统其至在某些场景32 核或者更多核的系统中也表现良好。
InnoDB概览
InnoDB 的数据存储在表空间 (tablespace)中,表空间是由InnoDB管理的一个黑盒子由一系列的数据文件组成。在MySQL 4.1以后的版本中InnoDB 可以将每个表的数据和索引存放在单独的文件中。InnoDB 也可以使用设备作为表空间的存储介质,但现代的文件系统使得裸设备不再是必要的选择。
InnoDB 采用 MVCC 来支持高并发,并且实现了四个标准的隔离级别。其默认级别是REPEATABLE READ(可重复读并且通过间隙锁(next-key locking)策略防止幻读的出现间隙锁使得InnoDB 不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定,以防止幻影行的插入。
InnoDB 表是基于聚索引建立的,我们会在后面的章节详细讨论聚簇索引。InnoDB的索引结构和 MySQL的其他存储引警有很大的不同,聚簇索引对主键查询有很高的性能不过它的二级索引 (secondary index,非主键索引)中必须包含主列,所以如果主铺列很大的话,其他的所有索引都会很大。因此,若表上的索引较多的话,主键应当尽可能的小。InnoDB 的存储格式是平台独立的,也就是说可以将数据和索引文件从Intel 平台复制到 PowerPC或者 Sun SPARC平台。
InnoDB 内部做了很多优化,包括从盘读取数据时采用的可预测性预读,能够自动在内存中创建 hash 索引以加速读操作的自适应哈希索引 (adaptive hash index),以及能够加速插入操作的插入缓冲区 (insert buffer)等。本书后面将更详细地讨论这些内容。
InnoDB 的行为是非常复杂的,不容易理解。如果使用了 InnoDB 引,笔者强烈建议阅读官方手册中的“InnDB 事务模型和锁”一节。如果应用序基于InnoDB 构建,则事先了解一下InnoDB的MVCC 架构带来的一些微妙和细节之处是非常有必要的。储擎要为所有用户甚至包括修改数据的用户维持一致性的视图,是非常复杂的工作。
作为事务型的存储引擎,InnoDB 通过一些机制和具支持真正的热备份,Oracle 提供的MySQL Enterprise Backup、Percona 提供的开源的 XtraBackup 都可以做到这一点。MySQL的其他存储引擎不支持热备份,要获取一致性视图需要停止对所有表的写入而在读写混合场景中,停止写入可能也意味着停止读取。

1.5.2 MyISAM存储引擎

在MySQL 5.1 及之前的版本,MyISAM是默认的存储引擎。MyISAM 提供了大量的特性,包括全文索引、压缩、空间函数 (GIS)等,但 MyISAM 不支持事务和行级锁,而且有一个毫无疑问的缺陷就是崩溃后无法安全恢复。正是由于 MyISAM 引的缘故,即使 MySQL 支持事务已经很长时间了,在很多人的概念中 MySQL 还是非事务型的数据库。尽管 MyISAM 引擎不支持事务、不支持崩后的安全恢复,但它绝不是一无是处的。对于只读的数据,或者表比较小、可以忍受修复 (repai)操作,则依然可以继续使用MyISAM(但请不要默认使用MyISAM,而是应当默认使用InoDB)。
存储
MyISAM会将表存在两个文件中:数据文件和索引文件,分别以MYD,MYI为扩展名。MyISAM表可以包含动态或者静态(长度固定)行MySQL 会根据表的定义来决定采用何种行格式。MyISAM 表可以储的行记录数,一般受限于可用的磁盘空间或者操作系统中单个文件的最大尺寸。
在MySQL 5.0中MyISAM 表如果是变长行,则默认配置只能处理256TB 的数据,因为指向数据记录的指针长度是 6 个字节。而在更早的版本中,指针长度默认是 4 字节,所以只能处理 4GB 的数据。而所有的 MySQL 版本都支持8字节的指针。要改变MyISAM 表指针的长度 (调高或者调低),可以通过修改表的 MAX_ROWS和AVG_ROWLENGTH选项的值来实现,两者相乘就是表可能达到的最大大小。修改这两个参数会导致重建整个表和表的所有索引,这可能需要很长的时间才能完成。
MyISAM特性
作为 MySQL最早的存储引擎之一,MyISAM 有一些已经开发出来很多年的特性,可以满足用户的实际需求。
加锁与并发
MyISAM 对整张表加锁,而不是针对行。读取时会对需要读到的所有表加共享锁写入时则对表加排他锁。但是在表有读取查询的同时,也可以往表中插人新的记录(这被称为并发插入,CONCURRENT INSERT)。
修复
对于MyISAM表,MySQL可以手工或者自动执行检查和修复操作,但这里说的修复和事务恢复以及崩恢复是不同的概念。执行表的修复可能导致一些数据丢失而且修复操作是非常慢的。可以通过 CHECK TABLE mytable 检查表的错误,如果有错误可以通过执行 REPAIR TABLE mytable进行修复。另外,如果MySQL服务器已经关闭,也可以通过 myisamchk 命令行工具进行检查和修复操作。
索引特性
对于MyISAM 表,即使是 BLOB 和 TEXT 等长字段,也可以基于其前 500 个字符创建索引。MyISAM 也支持全文索引,这是一种基于分词创建的索引,可以支持复杂的查询。关于索引的更多信息请参考第 5 章
延迟更新索引键 (Delayed Key Write)
创建MyISAM表的时候,如果指定了 DELAY KEY WRITE选项在每次修改执行完成时,不会立刻将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区 (in-emorykey buffer),只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入到磁盘。这种方式可以极大地提升写入性能,但是在数据库或者主机崩溃时会造成索引损坏,需要执行修复操作。延迟更新索引键的特性,可以在全局设置,也可以为单个表设置。
MyISAM压缩表
如果表在创建并导入数据以后,不会再进行修改操作,那么这样的表或许适合采用MyISAM 压缩表。
可以使用 myisampack对MyISAM 表进行压缩(也叫打包 pack)。压缩表是不能进行修改的(除非先将表解除压缩,修改数据,然后再次压缩)。压缩表可以极大地减少磁盘空间占用,因此也可以减少磁盘 I/0,从而提升查询性能。压缩表也支持索引,但索引也是只读的。
以现在的硬件能力,对大多数应用场景,读取压缩表数据时的解压带来的开销影响并不大,而减少I/0 带来的好处则要大得多。压缩时表中的记录是独立压缩的,所以读取单行的时候不需要去解压整个表 (甚至也不解压行所在的整个页面)。
MyISAM 性能
MyISAM 引擎设计简单,数据以紧密格式存储,所以在某些场景下的性能很好MyISAM 有一些服务器级别的性能扩展限制,比如对索引键缓冲区 (key cache)的Mutex 锁,MariaDB 基于段 (segment)的索引键缓冲区机制来避免该问题。但 MyISAM最典型的性能问题还是表锁的问题,如果你发现所有的查询都长期处于“Locked”状态那么毫无疑问表锁就是罪魁祸首。

1.5.3 MySQL内建的其他存储引擎

Archive 引擎
Archive存储引擎只支持 INSERT和SELECT操作,在MySQL 5.1之前也不支持索引。
Archive引警会缓存所有的写并利用zlib 对插的行进行压缩,所以比MyISAM的磁盘I/0更少但是每次SELECT查询都需要执行全表扫描。所以 Archive 表适合日志和数据采集类应用,这类应用做数据分析时往往需要全表扫描。或者在一些需要更快速的INSERT操作的场合下也可以使用。
Archive 引擎支持行级锁和专用的缓冲区,所以可以实现高并发的插入。在一个查询开始直到返回表中存在的所有行数之前,Archive 引会阻止其他的 SELECT执行,以实现一致性读。另外,也实现了批量插入在完成之前对读操作是不可见的。这种机制模仿了事务和MVCC的一些特性,但 Archive 引擎不是一个事务型的引攀,而是一个针对高速插入和压缩做了优化的简单引擎。
Blackhole 引擎
Blackhole引擎没有实现任何的存储机制,它会丢弃所有插入的数据,不做任何保存。但是服务器会记录 Blackhole 表的日志,所以可以用于复制数据到备库,或者只是简单地记录到日志。这种特殊的存储引擎可以在一些特殊的复制架构和日志审核时发挥作用。但这种应用方式我们碰到过很多问题,因此并不推荐
CSV引擎
CSV引擎可以将普通的 CSV 文件 (逗号分制值的文件)作为 MySQL 的表来处理,但这种表不支持索引。CSV引擎可以在数据库运行时拷入或者拷出文件。可以将 Excel等电子表格软件中的数据存储为 CSV 文件,然后复制到 MySQL 数据目录下,就能在MySQL中打开使用。同样,如果将数据写入到一个CSV引表,其他的外部程序也能立即从表的数据文件中读取CSV 格式的数据。因此CSV引可以作为一种数据交换的机制,非常有用。
Federated引擎
Federated引擎是访问其他 MySQL 服务器的一个代理,它会创建一个到远程MySQL服务器的客户端连接,并将查询传输到远程服务器执行,然后提取或者发送需要的数据最初设计该存储引擎是为了和企业级数据库如 Microsoft SQL Server 和 Oracle 的类似特性竞争的,可以说更多的是一种市场行为。尽管该引擎看起来提供了一种很好的跨服务器的灵活性,但也经常带来问题,因此默认是禁用的。MariaDB 使用了它的一个后续改进版本,叫做 FederatedX。
Memory 引擎
如果需要快速地访问数据,并且这些数据不会被修改,重启以后丢失也没有关系,那么使用Memory 表(以前也叫做 HEAP 表)是非常有用的。Memory 表至少比 MyISAM 表要快一个数量级,因为所有的数据都保存在内存中,不需要进行磁盘I/0。Memory 表的结构在重启以后还会保留,但数据会丢失。
Memroy 表在很多场景可以发挥好的作用:
用于查找(lookup)或者映射 (mapping)表,例如将邮编和州名映射的表用于缓存周期性聚合数据(periodically aggregated data)的结果。用于保存数据分析中产生的中间数据。
Memory 表支持 Hash索引,因此查找操作非常快。虽然 Memory 表的速度非常快,但还是无法取代传统的基于磁盘的表。Memroy 表是表级锁,因此并发写入的性能较低。它不支持 BLOB 或 TEXT 类型的列,并且每行的长度是固定的,所以即使指定了 VARCHAR列实际存储时也会转换成CHAR,这可能导致部分内存的浪费 (其中一些限制在 Percona版本已经)。
如果 MySQL在执行查询的过中需要使用临时表来保存中间结果,内部使用的临时表就是Memory表。如果中间结果太大超出了 Memory 表的限制,或者含有 BLOB 或TEXT宇段,则临时表会转换成MyISAM 表。在后续的章节还会继续讨论该问题。
人们经常混滑Memory 表和临时表。临时表是指使用CREATE TEMPORARY TABLE语创建的表,它可以使用任何存储引,因此和 Memory 表不是一回事。临时表只在单个连接中可见,当连接断开时,临时表也将不复存在。
Merge引擎
Merge引擎是 MyISAM引的一个变种。Merge 表是由多个 MyISAM 表合并而来的虚拟表。如果将 MySQL 用于日志或者数据库类应用,该引擎可以发挥作用。但是引入分区功能后,该引擎已经被放弃 (参考第7)
NDB集群引擎
2003 年,当时的 MySQL AB 公司从索尼爱立信公司收购了 NDB 数据库,然后开发了NDB 集群存储引擎,作为SQL和NDB 原生协议之间的接口。MySOL 服务器、NDB集群存储引擎,以及分布式的share-nothing 的、容灾的、高可用的 NDB 数据库的组合被称为MySQL集群(MySQL Cluster)。本书后续会有章节专门来讨论 MySQL 集群

1.5.4 第三方存储引擎

MySQL从2007 年开始提供了插件式的存储引擎 API,从此涌出了一系列为不同目的而设计的存储引擎。其中有一些已经合并到 MySQL 服务器,但大多数还是第三方产品或者开源项目。下面探讨一些我们认为在它设计的场景中确实很有用的第三方存储引擎。
OLTP类引擎
Percona的XtraDB存储引警是基于InnoDB引警的一个改进版本,已经包含在 PerconaServer和 MariaDB 中,它的改进点主要集中在性能、可测量性和操作灵活性方面XtraDB 可以作为InnoDB 的一个完全的代产品,甚至可以兼容地读写InnoDB 的数据文件,并支持 InnoDB的所查询。
另外还有一些和InnoDB 非常类似的OLTP 类存储引比如都支持ACID 事务和MVCC。其中一个就是PBXT,由 Paul McCullagh和Primebase GMBH开发。它支持引警级别的复制、外键约束,并且以一种比较复杂的架构对固态存储 (SSD)提供了适当的支持,还对较大的值类型如 BLOB 也做了优化。PBXT是一款社区支持的存储引擎MariaDB 包含了该引整
TokuDB引擎使用了一种新的叫做分形树 (Fractal Trees)的索引数据结构。该结构是缓存无关的,因此即使其大小超过内存性能也不会下降,也就没有内存生命周期和碎片的问题。TokuDB 是一种大数据 (Big Data)存储引攀,因为其拥有很高的压缩比,可以在很大的数据量上创建大量索引。在本书写作时,这个引擎还处于早期的生产版本状态在并发性方面还有很多明显的限制。目前其最适合在需要大量插入数据的分析型数据集的场景中使用,不过这些限制可能在后续版本中解决掉。
RethinkDB 最初是为固态存储 (SSD)而设计的,然而随时间的推移,目前看起来和最初的目标有一定的差距。该引擎比较特别的地方在于采用了一种只能迫加的写时复制B树(append-only copyon-write B-Tree)作为索引的数据结构。目前还处于早期开发状态我们还没有测试评估过,也没有听说有实际的应用案例。
在Sun 收购 MySQLAB 以后,Falcon 存储引擎曾经作为下一代存储引擎被寄予期望,但现在该项目已经被取消很久了。Falcon 的主要设计者 Jim Starkey 创立了一家新公司,主要做可以支持云计算的NewSQL 数据库产品,叫做 NuoDB (之前叫 NimbusDB)。
面向列的存储引擎
MySQL 默认是面向行的,每一行的数据是一起存储的,服务器的查询也是以行为单位处理的。而在大数据量处理时,面向列的方式可能效率更高。如果不需要整行的数据面向列的方式可以传输更少的数据。如果每一列都单独存储,那么压缩的效率也会更高
Infobright是最有名的面向列的存储引擎。在非常大的数据量 (数十 TB)时,该引作良好。Infobright 是为数据分析和数据仓库应用设计的。数据高度压缩,按照块进行排序,每个块都对应有一组元数据。在处理查询时,访问元数据可决定跳过该块,甚至可能只需要元数据即可满足查询的需求。但该引擎不支持索引,不过在这么大的数据量级即使有索引也很难发挥作用,而且块结构也是一种准索引 (quasi-index)。Infobright需要对 MySOL 服务器做定制,因为一些地方需要修改以适应面向列存储的需要。如果查询无法在存储层使用面向列的模式执行,则需要在服务器层转换成按行处理,这个过程会很慢。Infobright 有社区版和商业版两个版本
另外一个面向列的存储引擎是 Calpont 公司的 InfiniDB,也有社区版和商业版。InfiniDB可以在一组机器集群间做分布式查询,但目前还没有生产环境的应用案例。
顺便提一下,在 MySOL 之外,如果有面列的存储的需求,我们也评估过 LucidDB 和MonetDB。在我们的MySQL性能博客生 上有相应的性能测试数据或许随着时间的推移这些数据慢慢会过期,但依然可以作为参考。
社区存储引擎
如果要列举社区提供的所有存储引擎,可能会有两位数,甚至三位数。但是负责任地说其中大部分影响力有限,很多可能都没有听说过,或者只有极少人在使用。在这里列举了一些,也大都没有在生产环境中应用过,慎用,后果自负。

1.5.4 选择合适的引擎

这么多存储引擎,我们怎么选择?大部分情况下,InnoDB 都是正确的选择,所以 Oracle在MySQL5.5版本时终于将InnoDB 作为默认的存储引擎了。对于如何选择存储引擎可以简单地归纳为一句话:“除非需要用到某些InnoDB 不具性,并且没有其他法可以替代,否则都应该优先选择 InnoDB 引擎”。例如,如果要用到全文索引,建议优先考虑InnoDB 加上 Sphinx 的组合,而不是使用支持全文索引的 MyISAM。当然,如果不需要用到 InnoDB 的特性,同时其他引的特性能够更好地满足需求,也可以考虑一下其他储引擎。举个例子,如果不在乎可扩展能力和并发能力,也不在乎崩溃后的数据丢失问题,却对 InnoDB 的空间占用过多比较敏感,这种场合下选择 MyISAM 就比较合适。
除非万不得已,否则建议不要混合使用多种存储引擎,否则可能带来一系列复杂的问题以及一些潜在的 bug 和边界问题。存储引层和服务器层的交互已经比较复杂,更不用说混合多个存储引擎了。至少,混合存储对一致性备份和服务器参数配置都带来了一些困难
如果应用需要不同的存储引擎,请先考虑以下几个因素
事务
如果应用需要事务支持,那么InnoDB (者XtraDB)前定并经过验证的选择。如果不需要事务,并且主要是 SELECT 和 INSERT 操作,那么MyISAM是不错的选择。一般日志型的应用比较符合这一特性。
备份
备份的需求也会影响存储引擎的选择。如果可以定期地关闭服务器来执行备份,那么备份的因素可以忽略。反之,如果需要在线热备份,那么选择InnoDB 就是基本的要求。
崩溃恢复
数据量比较大的时候,系统崩溃后如何快速地恢复是一个需要考虑的问题。相对而言MyISAM 崩后发生损坏的概率比InnoDB 要高很多,而且复速度也要慢。因此即使不需要事务支持,很多人也选择 InnoDB 引擎,这是一个非常重要的因素。
特有的特性
最后,有些应用可能依赖一些存储引擎所独有的特性或者优化,比如很多应用依赖聚簇索引的优化。另外,MySOL中也只有 MyISAM 支持地理空间搜索。如果一个存储引擎拥有一些关键的特性,同时却又缺乏一些必要的特性,那么有时候不得不做折中的考虑,或者在架构设计上做一些取舍。某些存储引擎无法直接支持的特性有时候通过变通也可以满足需求。
不要轻易相信“MyISAM 比InnoDB 快”之类的经验之谈,这个结论往往不是绝对的在很多我们已知的场景中,InoDB 的速度都可以让 MyISAM 望及,尤其是使用到聚簇索引,或者需要访问的数据都可以放入内存的应用。在本书后续章节,读者可以了解更多影响存储引擎性能的因素(如数据大小I/0 请量、键还是二级索引等)以及这些因素对应用的影响。
当设计上述类型的应用时,建议采用InoDB。MyISAM引擎在一开始可能没有任何问题,但随着应用压力的上升,则可能迅速恶化。各种锁争用、崩溃后的数据丢失等问题都会随之而来。

转换表的引擎

有很多种方法可以将表的存储引擎转换成另外一种引擎。每种方法都有其优点和缺点在接下来的章节中,我们将讲述其中的三种方法。
ALTER TABLE
将表从一个引擎修改为另一个引擎最简单的办法是使用 ALTER TABLE语。下面的语句将mytable的引擎修改为InnoDB:
mysql>ALTER TABLE mytable ENGINE= InnoDB;
上述语法可以适用任何存储引擎。但有一个问题:需要执行很长时间。MySQL 会按行将数据从原表复制到一张新的表中,在复制期间可能会消耗系统所有的 I/0 能力,同时原表上会加上读锁。所以,在繁忙的表上执行此操作要特别小心。一个替代方案是采用接下来将讨论的导出与导人的方法,手工进行表的复制。
如果转换表的存储引擎,将会失去和原引攀相关的所有特性。例如,如果将一张 InnoDB表转换为MyISAM,然后再转换回 InnoDB,原InnoDB 表上所有的外键将丢失。
导出与导入
为了更好地控制转换的过程,可以使用 mysqldump 工具将数据导出到文件,然后修改文件中CREATE TABLE语的存储引选项,注同时修改表名,因为同一个数据库中不能存在相同的表名,即使它们使用的是不同的存储引。同时要注 mysgldump 默认会自动在CREATE TABLE语前加上DROP TABLE语,不注意这一点可能会导致数据丢失。
创建与查询(CREATE和SELECT)
第三种转换的技术综合了第一种方法的高效和第二种方法的安全。不需要导出整个表的数据,而是先创建一个新的存储引的表,然后利用 INSERT···SELECT 语法来导数据:

数据量不大的话,这样做工作得很好。如果数据量很大,则可以考虑做分批处理,针对每一段数据执行事务提交操作,以避免大事务产生过多的 undo。假设有主键字段 id,重复运行以下语 (最小值 和大值 y进行相应的换)将据导到新表:

这样操作完成以后,新表是原表的一个全量复制,原表还在,如果需要可以删除原表。
如果有必要,可以在执行的过程中对原表加锁,以确保新表和原表的数据一致。
Percona Toolkit提供了一个pt-online-schema-change的工具(基于Facebook的在线schema 变更技术),可以比较简单、方便地执行上述过程,避免手工操作可能导致的失误和烦琐。

标签:1.5,存储,架构,索引,引擎,InnoDB,MyISAM,MySQL
From: https://www.cnblogs.com/hhncoding/p/16943998.html

相关文章