MySQL InnoDB存储引擎(一):简介
2016 年 08 月 15 日
mysql

    对于MySQL,大家应该不会陌生,对于数据库,其最重要核心的功能就是如何存储,检索数据库,这将取决于其使用的存储引擎,在MySQL中,有一些可选的存储引擎,如InnoDBMyISAMMEMORY等,其中使用最为广泛的则是InnoDB,因为无论从高可用高性能等方面,其能满足大多数的应用场景,本文将对MySQLInnoDB存储引擎作一些基本简介,将基于MySQL 5.7

  • InnoDB存储引擎简介

  • InnoDB作为比较通用的存储引擎,其在高可用高性能两方面作了较好的平衡,因此也作为了MySQL的默认存储引擎。相较于其他存储引擎,InnoDB有几点关键的优势:

    DML操作支持ACID模型(关于ACID,可以看下之前的这篇文章),事务的提交回滚,以及在服务器崩溃后的恢复能力;
    具有的行级锁和Oracle风格的一致性读,以提升多用户的并发访问性能;
    InnoDB表会基于主键为查询操作作一些存储优化,每一个InnoDB表都具有一个叫作聚簇索引的主键索引,使得在进行主键查询时,可以最小化I/O操作;
    为了保证数据完整性InnoDB支持外键约束。通过外键,可以在进行数据插入,更新,删除时,对数据进行校验,以避免不同表之间的数据不一致问题。

    下表是InnoDB的一些特性:

  • 使用InnoDB表的好处

  • 相较于MyISAM等存储类型的表,InnoDB表具有以下一些优势:

    如果你的服务器因为硬件或软件原因导致崩溃,重启数据库后,并不需要作额外的工作,InnoDB将自动恢复处理,比如执行完崩溃前已经提交的事务回滚未提交的事务等;
    InnoDB存储引擎会维护自己的缓冲池,用于将表和索引数据缓存在内存中,因此频繁使用的数据将直接从内存中获取。对于专用的数据库服务器上,基本可以使用80%的内存用于该缓冲池;
    对于不同表之间的数据,InnoDB提供了外键约束来保证数据完整性
    如果数据在内存或磁盘中损坏,InnoDB校验和机制会在你使用该数据前,作出提醒;
    如果使用的InnoDB表具有主键列,那么涉及到主键列的一些操作会自动被优化,比如WHEREORDER BYGROUP BY等子句,或join操作;
    插入,更新,删除操作将被名为写缓冲区的机制自动优化,InnoDB不仅允许并发读写相同的表,并且能缓存更新的数据,以简化磁盘I/O操作;
    性能优势并不会受限于对大型表的长时间运行的查询操作,当表中某一行记录被反复访问时,InnoDB自适应哈希索引将使得这些查询变得更快,类似于从哈希表中获取数据;
    InnoDB允许压缩表和相关的索引;
    创建或删除索引对性能可用性影响很小;
    执行Truncate表十分高效,并能及时释放对应的磁盘空间供操作系统重用,而不是供InnoDB引擎重用;
    通过动态的行格式,对BLOB长文本数据类型的数据存储更有效;
    可以通过INFORMATION_SCHEMA表的数据监控存储引擎的内部运行状况;
    可以通过Performance Schema表的数据监控存储引擎的性能细节;
    可以混用InnoDB存储引擎与其他存储引擎,比如在同一个查询中join不同存储引擎的表;
    InnoDB在作处理大数据量时,针对CPU效率和最大性能作了针对设计;
    InnoDB能够处理大量数据,即使操作系统的文件大小限制为2G。
  • 有关InnoDB表的最佳实践

  • 以下是使用InnoDB表的一些最佳实践:

    为每张表指定一个主键,通常为需要频繁查询的列,如果没有明显的主键,可以指定一个自增列;
    在使用JOIN时,尽量基于记录ID(主键)。使用外键时,为了提升性能关联列被关联列应尽量使用相同数据类型。添加外建时,也尽量为被关联列添加索引;
    关闭自动提交,每秒成百上千次提交将直接影响性能(受限于存储设备的写速度);
    将多个相关的DML操作通过START TRANSACTIONCOMMIT包装为一个事务
    不要使用锁表语句,InnoDB表支持行锁( SELECT ... FOR UPDATE),允许并发读写同一张表的不同记录;
    开启innodb_file_per_table选项,使得每张表单独存储自己的数据和索引;
    评估数据存储和访问模式,是否会受益于compression特性(CREATE TABLE时指定ROW_FORMAT=COMPRESSED);
    运行Mysql Server时开启选项--sql_mode=NO_ENGINE_SUBSTITUTION,禁止表以不同的存储引擎创建,若有特例,可以通过CREATE TABLEENGINE=子句来指定。
  • 检查数据库是否支持InnoDB存储模型

  • 可以通过SHOW ENGINGES来检查当前数据库是否支持InnoDB

    mysql> SHOW ENGINES;
    +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
    | Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
    +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
    | InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
    | MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
    | MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
    | BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
    | MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
    | CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
    | ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
    | PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
    | FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
    +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
        

    或者直接查询INFORMATION_SCHEMA库的ENGINES表:

    mysql> use INFORMATION_SCHEMA;
    mysql> SELECT * FROM ENGINES;
    # 同上
        

    ENGINES中没有InnoDB,则可能需要重新安装支持InnoDB的MySQL版本;若InnoDB没有开启,在启动Mysql时,去掉skip-innodb相关的选项(这些选项在MySQL 5.7.5及之后已经无效)。另外,可以通过--default-storage-engine=InnoDB指定InnoDB为默认的存储引擎。

    若想禁用InnoDB存储引擎,可以在启动MySQL时使用--innodb=OFF参数。

  • InnoDB与ACID模型

  • ACID模型作为数据库设计的重要原则,其强调了对业务数据和关键应用的可靠性方面的重要性。MySQL包含了一些组件,如InnoDB存储引擎,实现了ACID模型,这样可以保证数据不会损坏,或者不会因为软件崩溃和硬件故障导致数据异常。当你的应用需要依赖ACID特性时,就不再需要再作一致性校验故障恢复等。如果你的应用已经从程序上保证了一定的一致性,或者具有高可靠的意见,又或应用允许一定的数据不一致,丢失等,那么你可以调整MySQLACID可靠性配置,以获取更好的性能吞吐量

  • InnoDB存储引擎如何与ACID模型相互作用

  • Atomicity(原子性)

  • InnoDB原子性主要体现在事务

    自动提交(Autocommit)设置;
    COMMIT语句;
    ROLLBACK语句;
    INFORMATION_SCHEMA表中可操作的数据;
  • Consistency(一致性)

  • InnoDB一致性主要体现在当服务器崩溃时,能保护数据

    InnoDB双写缓冲区(一种新型的文件刷新技术);
    InnoDB故障恢复
    ROLLBACK语句;
    INFORMATION_SCHEMA表中可操作的数据;
  • Isolation(隔离性)

  • InnoDB隔离性主要体现在事务,特别是隔离级别,与MySQL相关的特性有:

    SET ISOLATION LEVEL语句;
    InnoDB锁的底层细节,在性能调优时,可以通过INFORMATION_SCHEMA查看相关细节。
  • Durability(持久性)

  • InnoDB持久性主要体现在特性硬件上的影响,由于涉及到CPU网络存储设备等多个因素,若要提供出具体的配置策略方案,会比较困难。与持久性相关的MySQL特性大致有:

    InnoDB双写缓冲区,可通过innodb_doublewrite选项来开启或关闭;
    sync_binlog配置选项;
    innodb_file_per_table配置选项;
    存储设备中的写缓冲区,如磁盘驱动SSD,或RAID阵列
    运行MySQL的操作系统,特别是支持fsync()系统调用;
    对运行MySQL和保存MySQL数据的服务器,提供UPS保障;
    备份策略,如备份频率,备份类型,及备份保留时间;
    对于分布式托管数据的应用,MySQL服务器所在的数据中心的硬件特性,及数据中心间的网络连接;
  • InnoDB的多版本控制

  • InnoDB属于多版本控制的存储引擎:为了支持如并发回滚等事务特性,InnoDB会保存变更数据的多个旧版本,这些数据被保存在一个叫Rollback Segment的数据结构中(类似于Oracle),当事务回滚时,InnoDB将利用这些信息作一些必要的撤销操作,这些信息也用来作一些一致性读相关的操作。

    本质上,InnoDB内部保存记录时,会额外加上三个字段:

    字段名称 字段长度 描述
    DB_TRX_ID 6(Byte) 表示记录最后被插入或更新时对应的事务ID。对于删除操作,会被记作更新操作,并且其中一位用于标记为删除操作;
    DB_ROLL_PTR 7(Byte) 回滚指针。该指针指向回滚段(rollback segment)中的撤销日志记录(Undo Log Record),若某一行记录被更新了,该日志中将添加用于恢复记录被更新前的内容;
    DB_ROW_ID 6(Byte) 一个单调递增的行ID。

    位于回滚段中的撤销日志会被分为插入撤销日志更新撤销日志插入撤销日志主要用于事务回滚,一旦事务提交就可以被丢弃。更新撤销日志用于一致性读操作,仅能在没有事务存在时被删除,此时InnoDB会为一致性读操作创建一份来自更新撤销日志的快照。因此,你需要适当提交事务,包括一致性读操作,否则,InnoDB将不能删除掉相关的更新撤销日志,使得回滚文件太大。通常,撤销日志的大小会比对应插入或更新的数据库记录都小,这样就可以评估回滚文件所需要占用的磁盘大小。

    InnoDB的多版本模式中,当执行完DELETE语句后,数据库记录并不会立即物理删除,而只有当对应记录的更新撤销日志删除后,才会物理删除该记录,该操作叫purge(清除)

  • 多版本与二级索引

  • InnoDB多版本并发控制(MVCC)在处理二级索引时,与聚簇索引有所不同。聚簇索引中的记录可以直接更新,其隐藏的系统列指向撤销日志中的记录。与聚簇索引不同,二级索引记录不能直接更新,且不包含隐藏的系统列

    当更新二级索引列时,旧的二级索引记录将被标记为删除,然后插入新记录,最后清除标记为删除的二级索引记录。当二级索引记录被标记为删除,或二级索引页被新的事务更新时,InnoDB将在聚簇索引记录中查询对应的数据库记录。在聚簇索引记录中,将校验记录的DB_TRX_ID,如果在读事务启动后修改了记录,则从撤销日志中检索正确的记录版本。

    然而,如果启用索引条件下推(ICP)优化,并且可以仅使用索引中的字段来评估WHERE条件的部分,则MySQL服务器仍将WHERE条件的这部分下推到存储引擎使用索引。 如果没有找到匹配的记录,则避免查找聚集索引。 如果找到匹配的记录(即使在删除标记的记录中),InnoDB也会在聚集索引中查找记录。

  • 总结

  • 以上,则是InnoDB相关的基础简介,主要介绍了其特性,优势,及相关实践等。

  • 参考文献

好人,一生平安。