MySQL 存储引擎 InnoDB 和 MyISAM 有什么区别?

2025年 阅读约 12 分钟 面试指南 · MySQL

深入对比MySQL存储引擎InnoDB与MyISAM:事务支持、锁粒度、外键、崩溃恢复、MVCC、索引结构、适用场景,附面试模拟问答。

一句话总结

InnoDB 支持事务、行锁、外键、崩溃恢复(redo log),是 MySQL 5.5+ 默认引擎,适合 OLTP 场景。MyISAM 不支持事务、只有表锁、不支持外键,但查询速度快,适合读多写少的 OLAP 场景。核心区别:InnoDB 是"聚簇索引"(主键索引叶子存数据),MyISAM 是"非聚簇索引"(索引叶子存数据地址)。

初级理解

核心区别对比表

对比维度InnoDBMyISAM
事务✅ 支持(ACID)❌ 不支持
锁粒度行锁 + 间隙锁表锁
外键✅ 支持❌ 不支持
崩溃恢复✅ redo log 保证❌ 崩溃后需修复表
MVCC✅ 支持❌ 不支持
索引结构聚簇索引(B+树叶子存数据)非聚簇索引(B+树叶子存地址)
全文索引MySQL 5.6+ 支持✅ 原生支持
count(*)需要扫描有变量存储,O(1)
存储文件.ibd(数据和索引).MYD(数据)+ .MYI(索引)
适用场景OLTP(高并发读写)OLAP(读多写少)
# 查看表的存储引擎 SHOW TABLE STATUS LIKE 'users'; # 查看支持的存储引擎 SHOW ENGINES; # 建表时指定引擎 CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(50) ) ENGINE = InnoDB; # 修改表的存储引擎 ALTER TABLE users ENGINE = InnoDB;
一句话总结:InnoDB = 事务 + 行锁 + 崩溃恢复,MyISAM = 表锁 + 查询快 + 不支持事务。

中级深入

索引结构的本质区别

InnoDB 聚簇索引:主键索引的 B+树叶子节点存储完整行数据,二级索引叶子节点存储主键值(需要回表)。

MyISAM 非聚簇索引:主键索引和二级索引的 B+树叶子节点都存储数据行的物理地址,没有回表概念。

# InnoDB 查询过程 SELECT * FROM users WHERE name = '张三'; # 1. 在 name 索引 B+树中找到 name='张三' → 拿到主键 id=100 # 2. 用 id=100 去主键索引 B+树中查 → 拿到完整行数据(回表) # MyISAM 查询过程 SELECT * FROM users WHERE name = '张三'; # 1. 在 name 索引 B+树中找到 name='张三' → 拿到数据地址 0x1234 # 2. 直接去 .MYD 文件中地址 0x1234 读取数据(不需要回表)

为什么 MyISAM 查询比 InnoDB 快?

1. 不需要回表:索引直接指向数据地址

2. 没有事务开销:不需要维护 undo log、redo log、MVCC 版本链

3. count(*) 有缓存:表中有变量记录总行数

4. 表锁开销小:虽然并发差,但单次加锁开销比行锁小

InnoDB 为什么必须有主键?

InnoDB 使用聚簇索引组织数据,必须有主键来构建 B+树。如果建表时没有指定主键,InnoDB 会:

1. 找第一个 NOT NULL UNIQUE 索引作为聚簇索引

2. 如果都没有,自动生成一个隐藏的 6 字节 row_id 作为聚簇索引

# 推荐:显式指定自增主键 CREATE TABLE users ( id BIGINT AUTO_INCREMENT PRIMARY KEY, # 自增主键,插入效率高 name VARCHAR(50) ) ENGINE = InnoDB; # 不推荐:用 UUID 做主键 # UUID 是随机的,插入时会导致页分裂,性能差
中级要点:InnoDB 聚簇索引叶子存数据,MyISAM 叶子存地址;InnoDB 必须有主键,推荐自增整型。

高级拓展

Memory 引擎(HEAP)

数据全部存在内存中,重启后数据丢失。默认使用哈希索引,等值查询极快,但不支持范围查询。适合做临时表缓存表

# Memory 引擎特点 CREATE TABLE cache_table ( id INT PRIMARY KEY, data VARCHAR(100) ) ENGINE = Memory; # 注意: # 1. 表级锁(并发差) # 2. 不支持 TEXT/BLOB # 3. 重启后数据丢失 # 4. 适合:Session 存储、临时计算结果

如何选择存储引擎?

场景推荐引擎原因
电商订单系统InnoDB需要事务保证数据一致性
日志/审计表MyISAM 或 Archive只追加不修改,查询少
计数/统计表MyISAMcount(*) 快,无事务需求
Session 存储Memory数据可丢失,追求速度
全文搜索InnoDB(5.6+)或 ElasticsearchInnoDB 已支持全文索引

实战场景

场景:MyISAM 表迁移到 InnoDB

# 1. 检查当前引擎 SELECT TABLE_NAME, ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'mydb' AND ENGINE = 'MyISAM'; # 2. 批量生成 ALTER 语句 SELECT CONCAT('ALTER TABLE ', TABLE_NAME, ' ENGINE=InnoDB;') FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'mydb' AND ENGINE = 'MyISAM'; # 3. 迁移注意事项 # - 迁移前备份 # - 在低峰期执行(ALTER TABLE 会锁表) # - 使用 pt-online-schema-change 在线迁移(不锁表) pt-online-schema-change --alter "ENGINE=InnoDB" D=mydb,t=mytable --execute

面试模拟

面试官:InnoDB 和 MyISAM 有什么区别?

你:核心区别:1)InnoDB 支持事务和行锁,MyISAM 不支持事务只有表锁;2)InnoDB 是聚簇索引(主键叶子存数据),MyISAM 是非聚簇索引(叶子存地址);3)InnoDB 支持崩溃恢复(redo log),MyISAM 崩溃后需要修复表;4)InnoDB 支持外键和 MVCC,MyISAM 不支持。生产环境默认用 InnoDB。

面试官:为什么 InnoDB 推荐用自增主键?

你:InnoDB 使用聚簇索引,数据按主键顺序存储。自增主键每次插入都在最后,不会引起页分裂和页合并,插入效率最高。如果用 UUID 等随机主键,插入位置随机,会导致频繁的页分裂,降低写入性能,还会造成索引碎片。