深入剖析MySQL存储引擎:MyISAM与InnoDB的差异及选择指南

在日常开发中,我们通常主要使用 InnoDB 存储引擎,而对其他 MySQL 存储引擎的了解相对较少。但在面试中,尤其是校招面试时,存储引擎相关的基本问题常常会被问到。

本文总结了四个关于存储引擎的高频面试题,供大家参考:

  1. MySQL 支持哪些存储引擎?默认使用的是哪个?
  2. 你了解 MySQL 的存储引擎架构吗?
  3. MyISAM 和 InnoDB 有何不同?
  4. 如何选择 MyISAM 和 InnoDB?

MySQL 支持哪些存储引擎?默认使用的是哪个?

MySQL 支持多种存储引擎。你可以使用 SHOW ENGINES 命令查看 MySQL 支持的所有存储引擎。

查看 MySQL 提供的所有存储引擎

根据上图,我们可以看到,当前 MySQL 的默认存储引擎为 InnoDB。值得注意的是,在所有存储引擎中,唯有 InnoDB 支持事务。这意味着使用 InnoDB 可以确保数据的一致性。

当前使用的 MySQL 版本为 8.x,不同版本之间可能存在差异。在 MySQL 5.5.5 之前,MyISAM 是默认的存储引擎;而自 5.5.5 版本起,InnoDB 则成为新的默认选择。

你可以通过 SELECT VERSION() 命令查看你的 MySQL 版本。

mysql> SELECT VERSION();+-----------+| VERSION() |+-----------+| 8.0.27    |+-----------+1 row in set (0.00 sec)

此外,你还可以通过 SHOW VARIABLES LIKE '%storage_engine%' 命令直接查看 MySQL 当前的默认存储引擎。

mysql> SHOW VARIABLES  LIKE '%storage_engine%';+---------------------------------+-----------+| Variable_name                   | Value     |+---------------------------------+-----------+| default_storage_engine          | InnoDB    || default_tmp_storage_engine      | InnoDB    || disabled_storage_engines        |           || internal_tmp_mem_storage_engine | TempTable |+---------------------------------+-----------+4 rows in set (0.00 sec)

如果你希望更深入地了解各种存储引擎及其差异,建议阅读以下 MySQL 官方文档(面试中通常不会问得这么详细,了解即可):

你了解 MySQL 的存储引擎架构吗?

MySQL 存储引擎采用 插件式架构,支持多种存储引擎,我们甚至可以为不同的数据库表设置不同的存储引擎,以满足不同场景的需求。值得注意的是,存储引擎是基于表的,而非数据库

下图展示了 MySQL 具有可插拔存储引擎的架构:

MySQL 存储引擎架构图

你还可以根据 MySQL 定义的存储引擎实现标准接口,自行编写存储引擎。这些非官方提供的存储引擎被称为第三方存储引擎,与官方存储引擎有所区别。目前,InnoDB 其实最开始也是一个第三方存储引擎,后来凭借其卓越表现被 Oracle 收购。

关于如何编写自定义存储引擎的更多信息,请参考 MySQL 官方文档:自定义存储引擎

MyISAM 和 InnoDB 有何不同?

在 MySQL 5.5 之前,MyISAM 引擎是 MySQL 的默认存储引擎,曾一度风头无两。

尽管 MyISAM 的性能还不错,并具备一些特性(如全文索引、压缩、空间函数等),但它的缺陷也很明显:不支持事务和行级锁,且在崩溃后无法安全恢复。

自 MySQL 5.5 版本起,InnoDB 成为新的默认存储引擎。接下来,我们来对比一下两者的主要区别:

1. 行级锁的支持

MyISAM 仅支持表级锁(table-level locking),而 InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。这意味着 MyISAM 在写操作时会锁住整张表,这在高并发写入的情况下显得尤为低效,这也是 InnoDB 在并发写入时性能更佳的原因。

2. 事务支持

MyISAM 不提供事务支持,而 InnoDB 提供事务支持,符合 SQL 标准中定义的四个隔离级别,支持提交(commit)和回滚(rollback)操作。此外,InnoDB 默认使用的可重读隔离级别(REPEATABLE-READ)可以有效防止幻读问题(基于 MVCC 和 Next-Key Lock)。

3. 外键支持

MyISAM 不支持外键,而 InnoDB 支持。外键在维护数据一致性方面非常有帮助,但可能会对性能造成一定影响。因此,通常情况下,我们建议在实际生产项目中避免使用外键,转而在业务代码中进行约束。

阿里巴巴的《Java 开发手册》也明确规定禁止使用外键。

外键支持比较

不过,若在代码中施加约束,对程序员的能力要求也会相应提高,是否采用外键需要根据项目的实际情况来决定。

总结而言,通常我们不建议在数据库层面使用外键,而是在应用层解决此问题。然而,这可能会对数据的一致性造成风险。具体是否使用外键,仍需根据项目的特点来决定。

4. 异常崩溃后的安全恢复

MyISAM 不支持崩溃后的安全恢复,而 InnoDB 支持。使用 InnoDB 的数据库在遇到异常崩溃后,重启时会确保恢复到崩溃前的状态,这主要依赖于 redo log

5. MVCC的支持

MyISAM 不支持 MVCC,而 InnoDB 支持。实际上,这一对比是显而易见的,因为 MyISAM 连行级锁都不支持。MVCC 可以视为行级锁的升级,能够有效减少加锁操作,提高性能。

6. 索引实现的不同

虽然 MyISAM 和 InnoDB 都使用 B+Tree 作为索引结构,但两者的实现方式却截然不同。在 InnoDB 引擎中,数据文件本身就是索引文件;而在 MyISAM 中,索引文件和数据文件是分开的。InnoDB 的数据文件按照 B+Tree 的结构组织,而树的叶节点域中则保存了完整的数据记录。

7. 性能差异

相较于 MyISAM,InnoDB 的性能更为强大,无论是在读写混合模式还是只读模式中,InnoDB 的读写能力随着 CPU 核心数的增加而线性增长。而 MyISAM 在读写操作时无法并发,其处理能力与核心数无关。

InnoDB 和 MyISAM 性能对比

8. 缓存策略和机制的实现差异

InnoDB 使用缓冲池(Buffer Pool)缓存数据页和索引页,而 MyISAM 则使用键缓存(Key Cache),仅缓存索引页,而不缓存数据页。

总结

  • InnoDB 支持行级锁,MyISAM 只支持表级锁。
  • MyISAM 不支持事务,而 InnoDB 支持。
  • MyISAM 不支持外键,InnoDB 支持。
  • InnoDB 支持 MVCC,而 MyISAM 不支持。
  • 虽然两者都使用 B+Tree 作为索引结构,但实现方式有所不同。
  • MyISAM 不支持崩溃后的安全恢复,而 InnoDB 支持。
  • InnoDB 的性能普遍优于 MyISAM。

最后,再分享一幅图,详细对比几种常见的 MySQL 存储引擎。

常见的几种 MySQL 存储引擎对比

如何选择 MyISAM 和 InnoDB?

在大多数情况下,我们使用的都是 InnoDB 存储引擎,但在一些读密集型应用场景下,MyISAM 也可能是一个合理的选择。前提是你的项目能够接受 MyISAM 在事务支持、崩溃恢复等方面的缺陷(不过我们一般都不愿意妥协这些问题)。

正如《MySQL 高性能》一书所指出的:

不要轻易相信“ MyISAM 比 InnoDB 快”之类的偏见,这种结论往往并不绝对。在许多已知的场景下,InnoDB 的速度往往超过 MyISAM,尤其是在使用聚簇索引或者访问的数据可以完全放入内存的情况下。

通常情况下,选择 InnoDB 是可行的,但在一些特定场景下,如果你不在乎可扩展性、并发能力、事务支持,亦或崩溃后的安全恢复问题,选择 MyISAM 也不失为一个好选择。然而,通常我们都会考虑这些问题。