MyISAM vs InnoDB

MySQL 两大核心存储引擎 · 架构原理 · 核心区别 · 选型指南

MyISAM

MySQL 5.5 之前的默认引擎 · 起源于 ISAM

面向读多写少的简单场景,设计以性能和紧凑为目标,不支持事务、外键、行锁。 全表级锁机制使并发写性能极差,适合数据仓库、统计报表等读密集场景。

读速度快 占用空间小 全文索引 无事务 表级锁 崩溃不可靠 无外键

典型适用场景

📰 日志系统 / 只读数据仓库
📊 统计报表 / 历史归档数据
🔍 全文搜索(MySQL 5.6 前)

InnoDB

MySQL 5.5+ 默认引擎 · ACID 完整支持

生产环境首选,支持完整事务(ACID)、行级锁、外键约束、MVCC, 崩溃恢复能力强。适合高并发 OLTP 场景,是绝大多数互联网业务的标准选择。

ACID 事务 行级锁 MVCC 外键 崩溃恢复 内存占用大 空间稍大

典型适用场景

🛒 电商 / 金融 / 支付系统
👥 高并发 OLTP 业务
🔗 需要外键约束的复杂关系数据

核心特性对比

特性 MyISAM InnoDB
事务支持 ✗ 不支持 ✓ ACID 完整
锁粒度 表级锁(读共享/写独占) 行级锁(默认)
外键约束 ✗ 不支持 ✓ 支持
MVCC ✗ 不支持 ✓ 支持
崩溃恢复 弱(需修复) 强(Redo Log)
全文索引 ✓ 原生支持 ✓ 5.6+ 支持
COUNT(*) 性能 极快(存储总数) 需全表扫描
索引类型 非聚簇索引 聚簇索引(主键)
数据存储 .MYD(数据)+ .MYI(索引) .ibd(数据+索引合并)
内存缓存 仅缓存索引 数据 + 索引均缓存(Buffer Pool)
并发写入 差(表锁阻塞) 优秀(行锁并发)
适用场景 读多写少 / 统计 / 归档 高并发 OLTP / 金融 / 业务系统
🗂️ MyISAM 存储架构
SQL 层 & 查询优化器
MyISAM 存储引擎层
表级锁管理 · Key Cache(仅缓存索引)
文件系统 I/O
数据文件 & 索引文件完全分离
.MYD 数据文件
行数据存储
.MYI 索引文件
B+Tree 索引
.frm 表定义文件(结构描述)
⚠️ 关键特性
  • 非聚簇索引:索引文件中存储的是行的物理地址
  • Key Cache 只缓存索引,数据读取每次走 OS 磁盘 I/O
  • 写操作加表级独占锁,读写互斥
  • 存储行总数,COUNT(*) 直接返回
  • 无 Redo Log,崩溃后需 REPAIR TABLE
🏛️ InnoDB 存储架构
SQL 层 & 查询优化器
InnoDB Buffer Pool
数据页 + 索引页 统一缓存(默认128MB+)
Change Buffer · Adaptive Hash Index · Row-Level Lock
事务子系统(Undo Log + Redo Log + MVCC)
.ibd 表空间文件
数据+索引合并
redo Redo Log
崩溃恢复
undo Undo Log
事务回滚/MVCC
.frm 表定义文件
✅ 关键特性
  • 聚簇索引:数据直接存在主键 B+Tree 的叶节点
  • 二级索引叶节点存储主键值,需回表查询
  • Buffer Pool 统一缓存,减少磁盘 I/O
  • Redo Log 保证 WAL(Write-Ahead Logging)崩溃恢复
  • MVCC:读不加锁,读写并发不阻塞

索引结构差异:聚簇 vs 非聚簇

MyISAM — 非聚簇索引
索引 .MYI
B+Tree 根
key=1
→ 0x1A00
key=2
→ 0x1B40
数据 .MYD
0x1A00: row1 data
0x1B40: row2 data
...
索引叶节点 → 磁盘物理地址 → 读取数据
InnoDB — 聚簇索引
主键 B+Tree(数据即索引)
B+Tree 根节点
中间节点 (只存 key)
pk=1
完整行数据
pk=2
完整行数据
叶节点直接存完整行数据,无需二次 I/O
🔐 MyISAM 锁机制
📋
表级读锁(共享锁)
多个读操作可同时持有,但 SELECT 期间禁止任何写入。
🚫
表级写锁(独占锁)
写操作(INSERT/UPDATE/DELETE)独占整张表,其他读写全部阻塞,并发极差。
并发插入(CONCURRENT INSERT)
若数据文件无空洞,可开启并发在文件末尾追加,不阻塞读。
无事务 / 无 MVCC
不支持 BEGIN/COMMIT/ROLLBACK,无法保证数据一致性,崩溃可能丢数据。
🔓 InnoDB 锁 & 事务机制
🎯
行级锁(Record Lock)
默认锁定索引行,只阻塞竞争同一行的事务,高并发写入性能远优于表锁。
🔗
间隙锁 + 临键锁(GAP + Next-Key Lock)
可重复读级别下防止幻读,锁定索引范围,避免其他事务插入新行。
📸
MVCC 多版本并发控制
读操作创建快照,不加锁,读写不互斥,大幅提升并发读性能。
完整 ACID 事务
支持 BEGIN / COMMIT / ROLLBACK,Undo Log 支持回滚,Redo Log 保证持久性。

📈 并发场景下锁阻塞对比

场景:线程A写入行1,线程B读取行2(同一张表)
MyISAM
A 持有表级写锁 🔐
→ B 被阻塞 ⏳
InnoDB
A 持有行1锁
B 同时读取行2 ✅
场景:事务中途失败需回滚
MyISAM
无事务支持 — 数据写入后无法回滚 ❌
InnoDB
ROLLBACK — Undo Log 恢复数据 ✅
场景:高并发 COUNT(*) 查询
MyISAM
直接返回 ⚡ O(1)
InnoDB
扫描索引统计(MVCC 导致无法直接缓存总数)

InnoDB 事务隔离级别

隔离级别 脏读 不可重复读 幻读 说明
READ UNCOMMITTED 可能 可能 可能 性能最高,一致性最差
READ COMMITTED ✓ 解决 可能 可能 Oracle 默认级别
REPEATABLE READ ★ ✓ 解决 ✓ 解决 大部分解决 MySQL/InnoDB 默认,Next-Key Lock 防幻读
SERIALIZABLE ✓ 解决 ✓ 解决 ✓ 解决 串行执行,并发最差
※ MyISAM 无事务支持,以上隔离级别对 MyISAM 均不适用

全表读取

MyISAM
9/10
InnoDB
7.5/10
MyISAM 直接顺序读取数据文件,无事务开销

并发写入

MyISAM
2/10
InnoDB
9/10
表级锁 vs 行级锁,差距悬殊

COUNT(*)

MyISAM
10/10
InnoDB
4/10
MyISAM 存储总行数,O(1) 直接返回

点查询(主键)

MyISAM
7/10
InnoDB
9.2/10
InnoDB 聚簇索引一次 I/O 定位行数据

崩溃恢复

MyISAM
1.5/10
InnoDB
9.5/10
InnoDB WAL + Redo Log 保证崩溃自动恢复

内存占用

MyISAM
InnoDB
Buffer Pool 缓存数据+索引,内存换性能

磁盘文件对比

文件 MyISAM InnoDB
数据文件 .MYD(行数据) .ibd(数据+索引合并)
索引文件 .MYI(单独存放) 包含在 .ibd 内
表定义 .frm .frm(8.0 合并进 .ibd)
事务日志 ib_logfile0/1(Redo Log)
回滚日志 ibdata1 中的 Undo Log
文件碎片 DELETE 产生空洞,需 OPTIMIZE 页管理,碎片相对较少

选 MyISAM 的情况

(现代项目很少见,多为历史原因)
📊
纯读取统计分析表
数据只写入一次,反复 SELECT,无并发写,COUNT(*) 极频繁
🗄️
历史归档 / 日志表
数据仅 INSERT,从不 UPDATE/DELETE,不需要事务
💾
低配服务器 / 内存极紧张
MyISAM 内存占用远小于 InnoDB Buffer Pool
🔍
MySQL 5.6 之前的全文搜索
InnoDB 在 5.6 之前不支持 FULLTEXT 索引

选 InnoDB 的情况

(生产环境几乎所有场景的默认选择)
🛒
电商 / 金融 / 支付
订单、余额等需要严格 ACID 的核心业务,绝对不能丢数据
👥
高并发 OLTP
用户系统、社交、评论等频繁读写,行锁保证并发性能
🔗
有外键约束的关联数据
订单-商品-用户等多表关联,需外键保证参照完整性
🔁
任何需要事务的场景
转账、库存扣减等,任何需要 BEGIN/COMMIT/ROLLBACK 的操作
🔒
高可用 / 主从复制
Redo Log 使崩溃恢复可靠,是 MySQL 主从、MGR 的基础
💡

2024+ 项目的选型建议

新项目默认使用 InnoDB,无需考虑 MyISAM。 MySQL 5.5 起官方已将 InnoDB 设为默认引擎,5.6 起 InnoDB 也支持全文索引,MyISAM 的最后优势已基本消失。 InnoDB 的行级锁、MVCC、事务、崩溃恢复能力是现代生产系统的基本要求。

MyISAM 的最后价值: 系统表(mysql.* 元数据表)少量使用 MyISAM,以及极少数不需要任何事务保证的纯只读统计场景。