深入剖析MySQL存储引擎:MyISAM与InnoDB的差异及选择指南
在日常开发中,我们通常主要使用 InnoDB 存储引擎,而对其他 MySQL 存储引擎的了解相对较少。但在面试中,尤其是校招面试时,存储引擎相关的基本问题常常会被问到。
本文总结了四个关于存储引擎的高频面试题,供大家参考:
- MySQL 支持哪些存储引擎?默认使用的是哪个?
- 你了解 MySQL 的存储引擎架构吗?
- MyISAM 和 InnoDB 有何不同?
- 如何选择 MyISAM 和 InnoDB?
MySQL 支持哪些存储引擎?默认使用的是哪个?
MySQL 支持多种存储引擎。你可以使用 SHOW ENGINES
命令查看 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 定义的存储引擎实现标准接口,自行编写存储引擎。这些非官方提供的存储引擎被称为第三方存储引擎,与官方存储引擎有所区别。目前,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 在读写操作时无法并发,其处理能力与核心数无关。
8. 缓存策略和机制的实现差异
InnoDB 使用缓冲池(Buffer Pool)缓存数据页和索引页,而 MyISAM 则使用键缓存(Key Cache),仅缓存索引页,而不缓存数据页。
总结:
- InnoDB 支持行级锁,MyISAM 只支持表级锁。
- MyISAM 不支持事务,而 InnoDB 支持。
- MyISAM 不支持外键,InnoDB 支持。
- InnoDB 支持 MVCC,而 MyISAM 不支持。
- 虽然两者都使用 B+Tree 作为索引结构,但实现方式有所不同。
- MyISAM 不支持崩溃后的安全恢复,而 InnoDB 支持。
- InnoDB 的性能普遍优于 MyISAM。
最后,再分享一幅图,详细对比几种常见的 MySQL 存储引擎。
如何选择 MyISAM 和 InnoDB?
在大多数情况下,我们使用的都是 InnoDB 存储引擎,但在一些读密集型应用场景下,MyISAM 也可能是一个合理的选择。前提是你的项目能够接受 MyISAM 在事务支持、崩溃恢复等方面的缺陷(不过我们一般都不愿意妥协这些问题)。
正如《MySQL 高性能》一书所指出的:
不要轻易相信“ MyISAM 比 InnoDB 快”之类的偏见,这种结论往往并不绝对。在许多已知的场景下,InnoDB 的速度往往超过 MyISAM,尤其是在使用聚簇索引或者访问的数据可以完全放入内存的情况下。
通常情况下,选择 InnoDB 是可行的,但在一些特定场景下,如果你不在乎可扩展性、并发能力、事务支持,亦或崩溃后的安全恢复问题,选择 MyISAM 也不失为一个好选择。然而,通常我们都会考虑这些问题。