| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 大数据 -> mysql 存储引擎 -> 正文阅读 |
|
[大数据]mysql 存储引擎 |
目录 MySQL的存储引擎在文件系统中,MySQL将每个数据库(也可以称之为schema)保存为数据目录下的一 个子目录。创建表时,MySQL会在数据库子目录下创建一个和表同名的.frm文件保存 表的定义。例如创建一个名为MyTable的表,MySQL会在MyTable.frm文件中保存该表 的定义。因为MySQL使用文件系统的目录和文件来保存数据库和表的定义,大小写敏 感性和具体的平台密切相关。在Windows中,大小写是不敏感的,而在类Unix中则是 敏感的。不同的存储引擎保存数据和索引的方式是不同的,但表的定义则是在MySQL 服务层统一处理的。 可以使用SHOW TABLE STATUS命令(在MySQL 5.0以后的版本中,也可以查询 INFORMATION_SCHEMA中对应的表)显示表的相关信息。例如,对于mysql数据库中的 user表: Name 表名。 Engine 表的存储引擎类型。在旧版本中,该列的名字叫Type, 而不是Engine。 Row_format 行的格式。对于MyISAM表,可选的值为Dynamic、Fixed或者Compressed。 Dynamic的行长度是可变的,一般包含可变长度的字段,如VARCHAR或BLOB。Fixed的行长度则是固定的,只包含固定长度的列,如CHAR和INTEGER。Compressed的行 则只在压缩表中存在。 Rows 表中的行数。对于MylSAM和其他一些存储引擎,该值是精确的,但对于InnoDB, 该值是估计值。 Avg_row_length 平均每行包含的字节数。 Data_length 表数据的大小(以字节为单位)。 Max_data_length 表数据的最大容量,该值和存储引擎有关。 Index_length 索引的大小(以字节为单位)。 Data_free 对于MyISAM表,表示已分配但目前没有使用的空间。这部分空间包括了之前删除 的行,以及后续可以被INSERT利用到的空间。 Auto_ increment 下一个AUTO_ INCREMENT的值。 Create_ time 表的创建时间。 Update_ time 表数据的最后修改时间。 Check_time 使用CKECK TABLE命令或者myisamchk工具最后一次检查表的时间。 Collation 表的默认字符集和字符列排序规则。 Checksum 如果启用,保存的是整个表的实时校验和。 Create_ options 创建表时指定的其他选项。 Comment 该列包含了一些其他的额外信息。对于MyISAM表,保存的是表在创建时带的注释。 对于InnoDB表,则保存的是InnoDB表空间的剩余空间信息。如果是一个视图,则 该列包含"VIEW"的文本字样。 lnnoDB存储引擎InnoDB是MySQL的默认事务型引擎,也是最重要、使用最广泛的存储引擎。它被设计 用来处理大量的短期(short-Ii ved)事务,短期事务大部分情况是正常提交的,很少会 被回滚。InnoDB的性能和自动崩溃恢复特性,使得它在非事务型存储的需求中也很流 行。除非有非常特别的原因需要使用其他的存储引擎,否则应该优先考虑InnoDB引擎。 ?如果要学习存储引擎,InnoDB也是一个非常好的值得花最多的时间去深入学习的对象, 收益肯定比将时间平均花在每个存储引擎的学习上要高得多。 lnnoDB的历史InnoDB有着复杂的发布历史,了解一下这段历史对于理解InnoDB很有帮助。2008年, 发布了所谓的InnoDB plugin, 适用于MySQL 5.1版本,但这是Oracle创建的下一代 InnoDB引擎,其拥有者是InnoDB而不是MySQL。这基于很多原因,这些原因如果要 一一道来,恐怕得喝掉好几桶啤酒。MySQL默认还是选择了集成旧的InnoDB引擎。当 然用户可以自行选择使用新的性能更好、扩展性更佳的InnoDB plugin来覆盖旧的版本。 直到最后,在Oracle收购了Sun公司后发布的MySQL 5.5中才彻底使用InnoDB plugin 替代了旧版本的InnoDB (是的,这也意味着InnoDB plugin已经是原生编译了,而不是 编译成一个插件,但名字已经约定俗成很难更改)。 这个现代的InnoDB版本,也就是MySQL 5.1中所谓的InnoDB plugin, 支持一些新特性, 诸如利用排序创建索引(building index by sorting)、删除或者增加索引时不需要复制全 表数据、新的支持压缩的存储格式、新的大型列值如BLOB的存储方式,以及文件格式管 理等。很多用户在MySQL 5.1中没有使用InnoDB plugin, 或许是因为他们没有注意到 有这个区别。所以如果你使用的是MySQL 5.1, 一定要使用InnoDB plugin, 真的比旧 版本的InnoDB要好很多。 InnoDB是一个很重要的存储引擎,很多个人和公司都对其贡献代码,而不仅仅是 Oracle公司的开发团队。一些重要的贡献者包括Google、Yasufumi Kinoshita、Percona、 Facebook等,他们的一些改进被直接移植到官方版本,也有一些由InnoDB团队重新实现。 在过去的儿年间,InnoDB的改进速度大大加快,主要的改进集中在可测量性、可扩展性、 可配置化、性能、各种新特性和对Windows的支持等方面。MySQL 5.6实验室预览版 和里程碑版也包含了一系列重要的InnoDB新特性。 为改善InnoDB的性能,Oracle投入了大量的资源,并做了很多卓有成效的工作(外部 贡献者对此也提供了很大的帮助)。在本书的第二版中,我们注意到在超过四核CPU的 系统中InnoDB表现不佳,而现在已经可以很好地扩展至24核的系统,甚至在某些场景, 32核或者更多核的系统中也表现良好。很多改进将在即将发布的MySQL 5.6中引入,当然也还有机会做更进一步的改善。 lnnoDB概览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引擎,笔者强烈建议阅 读官方手册中的"InnoDB事务模型和锁"一节。如果应用程序基于InnoDB构建,则事 先了解一下InnoDB的MVCC架构带来的一些微妙和细节之处是非常有必要的。存储引 擎要为所有用户甚至包括修改数据的用户维持一致性的视图,是非常复杂的工作。 作为事务型的存储引擎,InnoDB通过一些机制和工具支持真正的热备份,Oracle提供 的MySQL Enterprise Backup、Percona提供的开源的XtraBackup都可以做到这一点。 MySQL的其他存储引擎不支持热备份,要获取一致性视图需要停止对所有表的写入, 而在读写混合场景中,停止写入可能也意味着停止读取。 Mysql与InnoDB架构图一张是 MySQL 架构图,另一张则是 InnoDB 架构图: 遇到问题,或者学习到新知识点时,就往里套,想一想,这是对应这两张图的哪个模块、是属于具体哪个成员的能力。 这其中,第一张图的最底下的存储引擎层(Storage Engines),它决定了 MySQL 会怎样存储数据,怎样读取和写入数据,也在很大程度上决定了 MySQL 的读写性能和数据可靠性。 对于这么重要的一层能力,MySQL 提供了极强的扩展性,你可以定义自己要使用什么样的存储引擎:InnoDB、MyISAM、MEMORY、CSV,甚至可以自己开发一个存储引擎然后使用它。 我一直觉得 MySQL 的设计,是教科书式的,高内聚松耦合,边界明确,职责清晰。学习 MySQL,学的不只是如何更好的使用 MySQL,更是学习如何更好的进行系统设计。 通常我们说 Mysql 高性能高可靠,都是指基于 InnoDB 存储引擎的 Mysql,所以,这一讲,先让我们来看看,除了 redo log,InnoDB 里还有哪些成员,他们都有什么能力,承担了什么样的角色,他们之间又是怎么配合的? InnoDB 内存架构从上面第二张图可以看到,InnoDB 主要分为两大块: InnoDB In-Memory Structures InnoDB On-Disk Structures 内存和磁盘,让我们先从内存开始。 1、Buffer Pool The buffer pool is an area in main memory where InnoDB caches table and index data as it is accessed. 正如之前提到的,MySQL 不会直接去修改磁盘的数据,因为这样做太慢了,MySQL 会先改内存,然后记录 redo log,等有空了再刷磁盘,如果内存里没有数据,就去磁盘 load。 而这些数据存放的地方,就是 Buffer Pool。 我们平时开发时,会用 redis 来做缓存,缓解数据库压力,其实 MySQL 自己也做了一层类似缓存的东西。 MySQL 是以「页」(page)为单位从磁盘读取数据的,Buffer Pool 里的数据也是如此,实际上,Buffer Pool 是a linked list of pages,一个以页为元素的链表。 为什么是链表?因为和缓存一样,它也需要一套淘汰算法来管理数据。 Buffer Pool 采用基于 LRU(least recently used) 的算法来管理内存: 2、Change Buffer 上面提到过,如果内存里没有对应「页」的数据,MySQL 就会去把数据从磁盘里 load 出来,如果每次需要的「页」都不同,或者不是相邻的「页」,那么每次 MySQL 都要去 load,这样就很慢了。 于是如果 MySQL 发现你要修改的页,不在内存里,就把你要对页的修改,先记到一个叫 Change Buffer 的地方,同时记录 redo log,然后再慢慢把数据 load 到内存,load 过来后,再把 Change Buffer 里记录的修改,应用到内存(Buffer Pool)中,这个动作叫做 merge;而把内存数据刷到磁盘的动作,叫 purge: merge:Change Buffer -> Buffer Pool purge:Buffer Pool -> Disk The change buffer is a special data structure that caches changes to secondary index pages when those pages are not in the buffer pool. The buffered changes, which may result from INSERT, UPDATE, or DELETE operations (DML), are merged later when the pages are loaded into the buffer pool by other read operations. 上面是 MySQL 官网对 Change Buffer 的定义,仔细看的话,你会发现里面提到:Change Buffer 只在操作「二级索引」(secondary index)时才使用,原因是「聚簇索引」(clustered indexes)必须是「唯一」的,也就意味着每次插入、更新,都需要检查是否已经有相同的字段存在,也就没有必要使用 Change Buffer 了;另外,「聚簇索引」操作的随机性比较小,通常在相邻的「页」进行操作,比如使用了自增主键的「聚簇索引」,那么 insert 时就是递增、有序的,不像「二级索引」,访问非常随机。 如果想深入理解 Change Buffer 的原理,除了 MySQL 官网的介绍:Change Buffer,还可以阅读下《MySQL技术内幕》的「2.6.1 - 插入缓冲」章节,里面会从 Change Buffer 的前身 —— Insert Buffer 开始讲起,很透彻。 3、Adaptive Hash Index MySQL 索引,不管是在磁盘里,还是被 load 到内存后,都是 B+ 树,B+ 树的查找次数取决于树的深度。你看,数据都已经放到内存了,还不能“一下子”就找到它,还要“几下子”,这空间牺牲的是不是不太值得? 尤其是那些频繁被访问的数据,每次过来都要走 B+ 树来查询,这时就会想到,我用一个指针把数据的位置记录下来不就好了? 这就是「自适应哈希索引」(Adaptive Hash Index)。自适应,顾名思义,MySQL 会自动评估使用自适应索引是否值得,如果观察到建立哈希索引可以提升速度,则建立。 4、Log Buffer The log buffer is the memory area that holds data to be written to the log files on disk. 从上面架构图可以看到,Log Buffer 里的 redo log,会被刷到磁盘里: Operating System Cache在内存和磁盘之间,你看到 MySQL 画了一层叫做 Operating System Cache 的东西,其实这个不属于 InnoDB 的能力,而是操作系统为了提升性能,在磁盘前面加的一层高速缓存,这里不展开细讲,感兴趣的同学可以参考下维基百科:Page Cache InnoDB 磁盘架构磁盘里有什么呢?除了表结构定义和索引,还有一些为了高性能和高可靠而设计的角色,比如 redo log、undo log、Change Buffer,以及 Doublewrite Buffer 等等. 有同学会问,那表的数据呢?其实只要理解了 InnoDB 里的所有表数据,都以索引(聚簇索引+二级索引)的形式存储起来,就知道索引已经包含了表数据。 1、表空间(Tablespaces) 从架构图可以看到,Tablespaces 分为五种: The System Tablespace File-Per-Table Tablespaces General Tablespace Undo Tablespaces Temporary Tablespaces 其中,我们平时创建的表的数据,可以存放到 The System Tablespace 、File-Per-Table Tablespaces、General Tablespace 三者中的任意一个地方,具体取决于你的配置和创建表时的 sql 语句。 这里同样不展开,如何选择不同的表空间存储数据?不同表空间各自的优势劣势等等,传送门:Tablespaces 2、Doublewrite Buffer 如果说 Change Buffer 是提升性能,那么 Doublewrite Buffer 就是保证数据页的可靠性。 怎么理解呢? 前面提到过,MySQL 以「页」为读取和写入单位,一个「页」里面有多行数据,写入数据时,MySQL 会先写内存中的页,然后再刷新到磁盘中的页。 这时问题来了,假设在某一次从内存刷新到磁盘的过程中,一个「页」刷了一半,突然操作系统或者 MySQL 进程奔溃了,这时候,内存里的页数据被清除了,而磁盘里的页数据,刷了一半,处于一个中间状态,不尴不尬,可以说是一个「不完整」,甚至是「坏掉的」的页。 有同学说,不是有 Redo Log 么?其实这个时候 Redo Log 也已经无力回天,Redo Log 是要在磁盘中的页数据是正常的、没有损坏的情况下,才能把磁盘里页数据 load 到内存,然后应用 Redo Log。而如果磁盘中的页数据已经损坏,是无法应用 Redo Log 的。 所以,MySQL 在刷数据到磁盘之前,要先把数据写到另外一个地方,也就是 Doublewrite Buffer,写完后,再开始写磁盘。Doublewrite Buffer 可以理解为是一个备份(recovery),万一真的发生 crash,就可以利用 Doublewrite Buffer 来修复磁盘里的数据。 MylSAM存储引擎在MySQL 5.1及之前的版本,MyISAM是默认的存储引擎。MylSAM提供了大量的特 性,包括全文索引、压缩、空间函数(GIS)等,但MyISAM不支持事务和行级锁,而且有一个毫无疑问的缺陷就是崩溃后无法安全恢复。正是由于MyISA.M引擎的缘故,即 使MySQL支持事务已经很长时间了,在很多人的概念中MySQL还是非事务型的数据 库。尽管MyISA.M引擎不支持事务、不支持崩溃后的安全恢复,但它绝不是一无是处 的。对于只读的数据,或者表比较小、可以忍受修复(repair)操作,则依然可以继续使 用MyISA.M (但请不要默认使用MylSA.M, 而是应当默认使用lnnoDB)。 存储MyISAM会将表存储在两个文件中:数据文件和索引文件,分别以.MYD和.MYI为扩 展名。MyISAM表可以包含动态或者静态(长度固定)行。MySQL会根据表的定义来 决定采用何种行格式。MyISAM表可以存储的行记录数,一般受限于可用的磁盘空间, 或者操作系统中单个文件的最大尺寸。 在MySQL 5.0中,MyISAM表如果是变长行,则默认配置只能处理256TB的数据,因 为指向数据记录的指针长度是6个字节。而在更早的版本中,指针长度默认是4字 节,所以只能处理4GB的数据。而所有的MySQL版本都支持8字节的指针。要改变 MyISAM表指针的长度(调高或者调低),可以通过修改表的MAX_ROWS和AVG_ROW_ LENGTH选项的值来实现,两者相乘就是表可能达到的最大大小。修改这两个参数会导致 重建整个表和表的所有索引,这可能需要很长的时间才能完成。 MylSAM特性作为MySQL最早的存储引擎之一,MyISAM有一些已经开发出来很多年的特性,可以 满足用户的实际需求。 加锁与并发 MyISAM对整张表加锁,而不是针对行。读取时会对需要读到的所有表加共享锁, 写入时则对表加排他锁。但是在表有读取查询的同时,也可以往表中插入新的记录 (这被称为并发插入,CONCURRENT INSERT)。 修复 对于MyISAM表,MySQL可以手工或者自动执行检查和修复操作,但这里说的修 复和事务恢复以及崩溃恢复是不同的概念。执行表的修复可能导致一些数据丢失, 而且修复操作是非常慢的。可以通过CHECK TABLE mytable检查表的错误,如果有 错误可以通过执行REPAIR TABLE mytable进行修复。另外,如果MySQL服务器已 经关闭,也可以通过myisamchk命令行工具进行检查和修复操作。 索引特性 对于MyISAM表,即使是BLOB和TEXT等长字段,也可以基于其前500个字符创建 索引。MyISAM也支持全文索引,这是一种基于分词创建的索引,可以支持复杂的 查询。 延迟更新索引键(Delayed Key Write)? ? ? ? ? ? ? ? ? ? ? ? ? 创建MyISAM表的时候,如果指定了DELAY_ KEY_ WRITE选项,在每次修改执行完成时,不会立刻将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区(in-memory key buffer), 只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入到磁盘。这种方式可以极大地提升写入性能,但是在数据库或者主机崩溃时会造成索引损坏,需要执行修复操作。延迟更新索引键的特性,可以在全局设置,也可以为单 个表设置。 MylSAM压缩表如果表在创建并导入数据以后,不会再进行修改操作,那么这样的表或许适合采用MyISAM压缩表。 可以使用myisampack对MyISAM表进行压缩(也叫打包pack)。压缩表是不能进行修 改的(除非先将表解除压缩,修改数据,然后再次压缩)。压缩表可以极大地减少磁盘 空间占用,因此也可以减少磁盘I/O, 从而提升查询性能。压缩表也支持索引,但索引 也是只读的。 以现在的硬件能力,对大多数应用场景,读取压缩表数据时的解压带来的开销影响并不 大,而减少I/O带来的好处则要大得多。压缩时表中的记录是独立压缩的,所以读取单 行的时候不需要去解压整个表(甚至也不解压行所在的整个页面)。 MylSAM性能MylSAM引擎设计简单,数据以紧密格式存储,所以在某些场景下的性能很好。 MyISAM有一些服务器级别的性能扩展限制,比如对索引键缓冲区(key cache)的 Mutex锁,MariaDB基于段(segment)的索引键缓冲区机制来避免该问题。但MylSAM 最典型的性能问题还是表锁的问题,如果你发现所有的查询都长期处于"Locked"状态, 那么毫无疑间表锁就是罪魁祸首。 Innodb与MyISAM的区别MyISAM是MySQL的默认数据库引擎(5.5版之前) 。虽然性能极佳,而且提供了大量的特性,包括全文索引、压缩、空间函数等,但MyISAM不支持事务和行级锁,而且最大的缺陷就是崩溃后无法安全恢复。不过, 5.5版本之后, MySQL引入了InnoDB (事务性数据库引擎) , MySQL 5.5版本后默认的存储引擎为InnoDB 大多数时候我们使用的都是InnoDB存储引擎,但是在某些情况下使用MyISAM也是合适的比如读密集的情况下。(如果你不介意MyISAM崩溃恢复问题的话) 两者的对比: 1.是否支持行级锁 MyISAM 只有表级锁(table-level locking),而 InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。 也就说,MyISAM 一锁就是锁住了整张表,这在并发写的情况下是多么滴憨憨啊!这也是为什么 InnoDB 在并发写的时候,性能更牛皮了! InnoDB 存储引擎的锁的算法有三种: Record lock:记录锁,单个行记录上的锁 Gap lock:间隙锁,锁定一个范围,不包括记录本身 Next-key lock:record+gap 临键锁,锁定一个范围,包含记录本身 2.是否支持事务 MyISAM 不提供事务支持。 InnoDB 提供事务支持,具有提交(commit)和回滚(rollback)事务的能力。 3.是否支持外键 MyISAM 不支持,而 InnoDB 支持。 一般我们也是不建议在数据库层面使用外键的,应用层面可以解决。不过,这样会对数据的一致性造成威胁。具体要不要使用外键还是要根据你的项目来决定。 4.是否支持数据库异常崩溃后的安全恢复 MyISAM 不支持,而 InnoDB 支持。 使用 InnoDB 的数据库在异常崩溃后,数据库重新启动的时候会保证数据库恢复到崩溃前的状态。这个恢复的过程依赖于 redo log 。 MySQL InnoDB 引擎使用 redo log(重做日志) 保证事务的持久性,使用 undo log(回滚日志) 来保证事务的原子性。 MySQL InnoDB 引擎通过 锁机制、MVCC 等手段来保证事务的隔离性( 默认支持的隔离级别是 REPEATABLE-READ )。 保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障。 5.是否支持 MVCC MyISAM 不支持,而 InnoDB 支持。 讲真,这个对比有点废话,毕竟 MyISAM 连行级锁都不支持。 MVCC 可以看作是行级锁的一个升级,可以有效减少加锁操作,提供性能。 一般情况下我们选择InnoDB都是没有问题的,但是某些情况下你并不在乎可扩展能力和并发能力,也不需要事务支持,也不在乎崩溃后的安全恢复问题的话,选择MyISAM也是一个不错的选择。但是一般情况下,我们都是需要考虑到这些问题的。? MySQL内建的其他存储引擎MySQL还有一些有特殊用途的存储引擎。在新版本中,有些可能因为一些原因已经不 再支持,另外还有些会继续支持,但是需要明确地启用后才能使用。 Archive引擎Archive存储引擎只支持INSERT和SELECT操作,在MySQL 5.1之前也不支持索引。 Archive引擎会缓存所有的写并利用zlib对插入的行进行压缩,所以比MylSAM表的磁 盘I/O更少。但是每次SELECT查询都需要执行全表扫描。所以Archive表适合日志和 数据采集类应用,这类应用做数据分析时往往需要全表扫描。或者在一些需要更快速的 INSl;RT操作的场合下也可以使用。 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表至少比MylSAM表 要快一个数量级,因为所有的数据都保存在内存中,不需要进行磁盘I/O。Memory表的 结构在重启以后还会保留,但数据会丢失。 Memroy表在很多场景可以发挥好的作用:
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. 用于日志或者数据仓库类应用,该引擎可以发挥作用。但是引入 分区功能后,该引擎已经被放弃。 NDB集群引擎2003年,当时的MySQLAB公司从索尼爱立信公司收购了NDB数据库,然后开发了 NDB集群存储引擎,作为SQL和NDB原生协议之间的接口。MySQL服务器、NDB集 群存储引擎,以及分布式的、share-nothing的、容灾的、高可用的NDB数据库的组合, 被称为MySQL集群(MySQL Cluster)。 第三方存储引擎MySQL从2007年开始提供了插件式的存储引擎API, 从此涌出了一系列为不同目的而 设计的存储引擎。其中有一些已经合并到MySQL服务器,但大多数还是第三方产品或 者开源项目。下面探讨一些我们认为在它设计的场景中确实很有用的第三方存储引擎。 OLTP类引擎Percona的XtraDB存储引擎是基于InnoDB引擎的一个改进版本,已经包含在Percona Server和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 copy on-write B-Tree)作为索引的数据结构。目前还处于早期开发状态, 我们还没有测试评估过,也没有听说有实际的应用案例。 在Sun收购MySQLAB以后,Falcon存储引擎曾经作为下一代存储引擎被寄予期望,但 现在该项目已经被取消很久了。Falcon的主要设计者Jim Starkey创立了一家新公司,主 要做可以支持云计算的NewSQL数据库产品,叫做NuoDB (之前叫NimbusDB)。 面向列的存储引擎MySQL默认是面向行的,每一行的数据是一起存储的,服务器的查询也是以行为单位 处理的。而在大数据量处理时,面向列的方式可能效率更高。如果不需要整行的数据,面向列的方式可以传输更少的数据。如果每一列都单独存储,那么压缩的效率也会更高。 lnfobright是最有名的面向列的存储引擎。在非常大的数据量(数十TB)时,该引擎工 作良好。Info bright是为数据分析和数据仓库应用设计的。数据高度压缩,按照块进行排 序,每个块都对应有一组元数据。在处理查询时,访间元数据可决定跳过该块,甚至可 能只需要元数据即可满足查询的需求。但该引擎不支持索引,不过在这么大的数据量级, 即使有索引也很难发挥作用,而且块结构也是一种准索引(quasi-index)。Info bright需要对MySQL服务器做定制,因为一些地方需要修改以适应面向列存储的需要。如果查 询无法在存储层使用面向列的模式执行,则需要在服务器层转换成按行处理,这个过程 会很慢。Info bright有社区版和商业版两个版本。 另外一个面向列的存储引擎是Calpont公司的lnfiniDB, 也有社区版和商业版。InfiniDB 可以在一组机器集群间做分布式查询,但目前还没有生产环境的应用案例。 顺便提一下,在MySQL之外,如果有面向列的存储的需求,我们也评估过LucidDB和 MonetDB。在我们的MySQL性能博客注5上有相应的性能测试数据,或许随着时间的推移, 这些数据慢慢会过期,但依然可以作为参考。 社区存储引擎如果要列举社区提供的所有存储引擎,可能会有两位数,甚至三位数。但是负责任地说, 其中大部分影响力有限,很多可能都没有听说过,或者只有极少人在使用。在这里列举 了一些,也大都没有在生产环境中应用过,慎用,后果自负。 Aria 之前的名字是Maria, 是MySQL创建者计划用来替代MyISAM的一款引擎。 MariaDB包含了该引擎,之前计划开发的很多特性,有些因为在MariaDB服务器层 实现,所以引擎层就取消了。在本书写作之际,可以说Aria就是解决了崩溃安全恢 复问题的MyISAM, 当然也还有一些特性是MyISAM不具备的,比如数据的缓存 (MyISAM只能缓存索引)。 Groonga 这是一款全文索引引擎,号称可以提供准确而高效的全文索引。 OQGraph 该引擎由Open Query研发,支持图操作(比如查找两点之间的最短路径),用SQL 很难实现该类操作。 Q4M 该引擎在MySQL内部实现了队列操作,而用SQL很难在一个语句实现这类队列 操作。 SJJhinxSE 该引擎为S_phinx全文索引搜索服务器提供了SQL接口。 Spider 该引擎可以将数据切分成不同的分区,比较高效透明地实现了分片(shard), 并且 可以针对分片执行并行查询(分片可以分布在不同的服务器上)。 VPForMySQL 该引擎支持垂直分区,通过一系列的代理存储引擎实现。垂直分区指的是可以将表 分成不同列的组合,并且单独存储。但对查询来说,看到的还是一张表。该引擎和 S_pider的作者是同一人。 选择合适的引擎这么多存储引擎,我们怎么选择?大部分情况下,InnoDB都是正确的选择,所以Oracle 在MySQL 5.5版本时终于将InnoDB作为默认的存储引擎了。对于如何选择存储引擎, 可以简单地归纳为一句话:“除非需要用到某些InnoDB不具备的特性,并且没有其他办 法可以替代,否则都应该优先选择InnoDB引擎"。例如,如果要用到全文索引,建议优 先考虑InnoDB加上Sphinx的组合,而不是使用支持全文索引的MyISAM。当然,如果 不需要用到InnoDB的特性,同时其他引擎的特性能够更好地满足需求,也可以考虑一 下其他存储引擎。举个例子,如果不在乎可扩展能力和井发能力,也不在乎崩溃后的数 据丢失问题,却对InnoDB的空间占用过多比较敏感,这种场合下选择MylSAM就比较 合适。 除非万不得已,否则建议不要混合使用多种存储引擎,否则可能带来一系列复杂的问题, 以及一些潜在的bug和边界问题。存储引擎层和服务器层的交互已经比较复杂,更不用 说混合多个存储引擎了。至少,混合存储对一致性备份和服务器参数配置都带来了一些 困难。 如果应用需要不同的存储引擎,请先考虑以下几个因素。 事务 如果应用需要事务支持,那么InnoDB (或者XtraDB)是目前最稳定并且经过验证 的选择。 如果不需要事务,并且主要是SELECT和INSERT操作,那么MyISAM是不 错的选择。一般日志型的应用比较符合这一特性。 备份 备份的需求也会影响存储引擎的选择。如果可以定期地关闭服务器来执行备份,那么备份的因素可以忽略。反之,如果需要在线热备份,那么选择InnoDB就是基本 的要求。 崩溃恢复 数据量比较大的时候,系统崩溃后如何快速地恢复是一个需要考虑的问题。相对而言,MyISAM崩溃后发生损坏的概率比InnoDB要高很多,而且恢复速度也要慢。因此, 即使不需要事务支持,很多人也选择InnoDB引擎,这是一个非常重要的因素。 特有的特性 最后,有些应用可能依赖一些存储引擎所独有的特性或者优化,比如很多应用依赖 聚簇索引的优化。另外,MySQL中也只有MyISAM支持地理空间搜索。如果一个 存储引擎拥有一些关键的特性,同时却又缺乏一些必要的特性,那么有时候不得不 做折中的考虑,或者在架构设计上做一些取舍。某些存储引擎无法直接支持的特性, 有时候通过变通也可以满足需求。 如果无法确定,那么就使用InnoDB, 这个 默认选项是安全的,尤其是搞不清楚具体需要什么的时候。 日志型应用假设你需要实时地记录一台中心电话交换机的每一通电话的日志到MySQL中,或者通 过Apache的mod_log_sql模块将网站的所有访问信息直接记录到表中。这一类应用的插 入速度有很高的要求,数据库不能成为瓶颈。MyISAM或者Archive存储引擎对这类应 用比较合适,因为它们开销低,而且插入速度非常快。 如果需要对记录的日志做分析报表,则事情就会变得有趣了。生成报表的SQL很有可能 会导致插入效率明显降低,这时候该怎么办? 一种解决方法,是利用MySQL内置的复制方案将数据复制一份到备库,然后在备库上 执行比较消耗时间和CPU的查询。这样主库只用于高效的插入工作,而备库上执行的查询也无须担心影响到日志的插入性能。当然也可以在系统负载较低的时候执行报表查询 操作,但应用在不断变化,如果依赖这个策略可能以后会导致问题。 另外一种方法,在日志记录表的名字中包含年和月的信息,比如web_logs_2012_01或者web_logs_2012_jan。这样可以在已经没有插人操作的历史表上做频繁的查询操作,而不 会干扰到最新的当前表上的插入操作。 只读或者大部分情况下只读的表有些表的数据用于编制类目或者分列清单(如工作岗位、竞拍、不动产等),这种应用 场景是典型的读多写少的业务。如果不介意MylSAM的崩溃恢复问题,选用MyISAM 引擎是合适的。不过不要低估崩溃恢复问题的重要性,有些存储引擎不会保证将数据安 全地写入到磁盘中,而许多用户实际上并不清楚这样有多大的风险(MyISAM只将数据 写到内存中,然后等待操作系统定期将数据刷出到磁盘上)。 一个值得推荐的方式,是在性能测试环境模拟真实的环境,运行应用,然后拔下电 源模拟崩溃测试。对崩溃恢复的第一手测试经验是无价之宝,可以避免真的碰到崩溃时手足无措。 不要轻易相信"MyISAM比InnoDB快”之类的经验之谈,这个结论往往不是绝对的。 在很多我们已知的场景中,InnoDB的速度都可以让MyISAM望尘莫及,尤其是使用到 聚簇索引,或者需要访问的数据都可以放入内存的应用。 当设计上述类型的应用时,建议采用InnoDB。MylSAM引擎在一开始可能没有任何问 题,但随着应用压力的上升,则可能迅速恶化。各种锁争用、崩溃后的数据丢失等问题 都会随之而来。 订单处理?如果涉及订单处理,那么支持事务就是必要选项。半完成的订单是无法用来吸引用户的。 另外一个重要的考虑点是存储引擎对外键的支持情况。InnoDB是订单处理类应用的最 佳选择。 电子公告牌和主题讨论论坛对于MySQL用户,主题讨论区是个很有意思的话题。当前有成百上于的基于PHP或者 Perl的免费系统可以支持主题讨论。其中大部分的数据库操作效率都不高,因为它们大 多倾向于在一次请求中执行尽可能多的查询语句。另外还有部分系统设计为不采用数据 库,当然也就无法利用到数据库提供的一些方便的特性。主题讨论区一般都有更新计数 器,并且会为各个主题计算访问统计信息。多数应用只设计了几张表来保存所有的数据, 所以核心表的读写压力可能非常大。为保证这些核心表的数据一致性,锁成为资源争 用的主要因素。 尽管有这些设计缺陷,但大多数应用在中低负载时可以工作得很好。如果Web站点的规 模迅速扩展,流量随之猛增,则数据库访问可能变得非常慢。此时一个典型的解决方案 是更改为支持更高读写的存储引擎,但有时用户会发现这么做反而导致系统变得更慢了。 用户可能没有意识到这是由于某些特殊查询的缘故,典型的如: mysql> SELECT COUNT(*)FROM table; 问题就在于,不是所有的存储引擎运行上述查询都非常快:对于MyISAM确实会很快, 但其他的可能都不行。每种存储引擎都能找出类似的对自己有利的例子。 CD-ROM应用如果要发布一个基于CD-ROM或者DVD-ROM井且使用MySQL数据文件的应用,可 以考虑使用MylSAM表或者MyISAM压缩表,这样表之间可以隔离并且可以在不同介 质上相互拷贝。MyISAM压缩表比未压缩的表要节约很多空间,但压缩表是只读的。在 某些应用中这可能是个大问题。但如果数据放到只读介质的场景下,压缩表的只读特性 就不是问题,就没有理由不采用压缩表了。 大数据量什么样的数据量算大?我们创建或者管理的很多InnoDB数据库的数据量在3 - 5TB之 间,或者更大,这是单台机器上的量,不是一个分片(shard)的量。这些系统运行得还 不错,要做到这一点需要合理地选择硬件,做好物理设计,并为服务器的I/O瓶颈做好 规划。在这样的数据量下,如果采用MyISAM, 崩溃后的恢复就是一个噩梦。 如果数据量继续增长到10TB以上的级别,可能就需要建立数据仓库。lnfobright是MySQL数据仓库最成功的解决方案。也有一些大数据库不适合Info bright, 却可能适合TokuDB。 转换表的引擎有很多种方法可以将表的存储引擎转换成另外一种引擎。每种方法都有其优点和缺点。 我们将讲述其中的三种方法。 ALTER TABLE将表从一个引擎修改为另一个引擎最简单的办法是使用ALTER TABLE语句。下面的语句 将mytable的引擎修改为InnoDB: mysql> ALTER TABLE mytable ENGINE= InnoDB; 上述语法可以适用任何存储引擎。但有一个问题:需要执行很长时间。MySQL会按行 将数据从原表复制到一张新的表中,在复制期间可能会消耗系统所有的I/O能力,同时 原表上会加上读锁。所以,在繁忙的表上执行此操作要特别小心。一个替代方案是采用 接下来将讨论的导出与导人的方法,手工进行表的复制。 如果转换表的存储引擎,将会失去和原引擎相关的所有特性。例如,如果将一张InnoDB 表转换为MyISAM, 然后再转换回InnoDB, 原InnoDB表上所有的外键将丢失。 导出与导入为了更好地控制转换的过程,可以使用mysqldump工具将数据导出到文件,然后修改文 件中CREATE TABLE语句的存储引擎选项,注意同时修改表名,因为同一个数据库中不能 存在相同的表名,即使它们使用的是不同的存储引擎。同时要注意mysqldump默认会自 动在CREATE TABLE语句前加上DROP TABLE语句,不注意这一点可能会导致数据丢失。 创建与查询(CREATE和SELECT)第三种转换的技术综合了第一种方法的高效和第二种方法的安全。不需要导出整个表的数据,而是先创建一个新的存储引擎的表,然后利用INSERT…SELECT语法来导数据: mysql> CREATE TABLE innodb_table LIKE myisam_table; mysql> ALTER TABLE innodb_table ENGINE=InnoDB; mysql> INSERT INTO innodb_table SELECT* FROM myisam_table; 数据量不大的话,这样做工作得很好。如果数据量很大,则可以考虑做分批处理,针对每一段数据执行事务提交操作,以避免大事务产生过多的undo。假设有主键字段id, 重复运行以下语句(最小值x和最大值y进行相应的替换)将数据导人到新表: mysql> START TRANSACTION; mysql> INSERT INTO innodb table SELECT* FROM myisam_table 一> WHERE id BETWEEN x AND y; mysql> CONMIT; 这样操作完成以后,新表是原表的一个全量复制,原表还在,如果需要可以删除原表。 如果有必要,可以在执行的过程中对原表加锁,以确保新表和原表的数据一致。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 0:53:48- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |