MySQL存储引擎该怎么选
聊聊MySQL里InnoDB、MyISAM、Memory这几个常见存储引擎的差别,从事务、锁、索引结构到崩溃恢复挨个比一遍,顺便说说为什么现在建表默认就是InnoDB,别的引擎啥时候还有用。
MySQL 存储引擎该怎么选
前段时间帮朋友排查一个老项目,建表语句里写着 ENGINE=MyISAM,一查年头,还是十年前抄的模板。
现在默认早就是 InnoDB 了,但很多老项目、老教程还停留在过去,甚至有人根本不知道 MySQL 还能选引擎。
今天我们就把常见的几个存储引擎捋一遍,搞清楚它们到底差在哪,什么时候该用哪个。
存储引擎是个啥
先说清楚一个概念:存储引擎决定的是数据在磁盘/内存里怎么存、怎么取、怎么加锁,跟 SQL 语法本身没关系。
打个比方,MySQL 就像一个仓库管理系统,存储引擎就是具体的货架和搬运方式。
货架可以用铁架子(InnoDB),也可以用纸箱堆叠(MyISAM),管理系统的操作界面(SQL)是一样的,但底层存取效率、能不能上锁保护、断电了货物还在不在,完全是两套逻辑。
查看当前数据库支持哪些引擎,直接一条命令:
-- 老王的表都用什么引擎,一眼就能看出来
SHOW ENGINES;
查具体某张表用的引擎:
SHOW TABLE STATUS LIKE 'mebugs_post';
-- 或者直接查 information_schema
SELECT TABLE_NAME, ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'site_ol';
InnoDB:现在的默认选项
MySQL 5.5 之后,InnoDB 就是默认引擎了。我们现在建表不写 ENGINE 关键字,跑出来的就是它。
核心特性就这么几个:
- 支持事务:满足 ACID,能
BEGIN、COMMIT、ROLLBACK,出错了能回滚,这对订单、支付这类场景是刚需。 - 支持行级锁:只锁被改动的那一行,并发写入的时候不会像表锁那样一锅端。
- 支持外键约束:能在数据库层面保证关联数据的一致性。
- 崩溃恢复能力强:靠 redo log 保证即使数据库宕机重启,也能把没落盘的数据恢复回来。
- 索引结构是聚簇索引(Clustered Index):数据本身就按主键顺序存储在 B+ 树的叶子节点上,主键查询效率很高。
举个事务的例子,我们平时最常写的转账场景:
-- 老张给老王转100块,这两步必须绑在一起,要么都成要么都不成
START TRANSACTION;
UPDATE account SET balance = balance - 100 WHERE user_id = 'zhang';
UPDATE account SET balance = balance + 100 WHERE user_id = 'wang';
COMMIT;
-- 如果中间任何一步出错,执行 ROLLBACK,两条更新都不会生效
如果用不支持事务的引擎,这两条 UPDATE 中间要是断电了,钱就可能只扣不加,等着老张来找你麻烦吧。
InnoDB 的代价是什么?相对 MyISAM,它的存储空间占用更大一些,纯读场景下性能也不一定是最优的,毕竟维护事务和锁本身就有额外开销。
但对绝大部分业务场景,这个代价完全值得,所以现在几乎所有新项目都不假思索直接用它。
MyISAM:曾经的默认,现在的过去式
MyISAM 是 MySQL 5.5 之前的默认引擎,现在基本只在老项目里能见到。
它的特点跟 InnoDB 正好形成对照:
- 不支持事务:没有
ROLLBACK,改错了没法反悔。 - 表级锁:修改一条数据,整张表都被锁住,高并发写入场景下性能会很拉。
- 不支持外键:关联关系只能靠业务代码自己保证。
- 索引是非聚簇的:索引和数据是分开存储的,索引里存的是数据的物理地址,查询命中索引后还要多一次寻址。
- 崩溃后容易损坏:断电或者异常关闭,表文件容易损坏,需要手动
REPAIR TABLE修复。
那 MyISAM 是不是完全没用了?倒也不是。
它的读性能在某些纯查询场景下确实能更快一点,而且表级锁在只读或者读多写少的场景下反而不是瓶颈。
早年很多做全文搜索、日志归档的表会用 MyISAM,因为那会儿 InnoDB 还不支持全文索引(FULLTEXT),MyISAM 支持。
不过 InnoDB 从 MySQL 5.6 开始也支持全文索引了,这个历史优势基本也消失了。
现在我个人的建议是:新项目直接忘掉这个引擎就行,除非你在维护一个十年前的老系统。
Memory:数据放内存里,图一个快
Memory 引擎(曾叫 HEAP)把所有数据直接放进内存,不落盘。
特点很直接:
- 速度极快:内存读写,没有磁盘 I/O 开销。
- 数据库重启数据就没了:因为压根没往磁盘写,服务一重启,表是空的。
- 不支持大字段类型:像
TEXT、BLOB这种大对象类型存不了。 - 默认用哈希索引:等值查询飞快,但范围查询(
>、<、BETWEEN)效率不行。
这个引擎适合什么场景?临时表、会话缓存、验证码之类短命数据的中间存储,或者一些查询频繁但允许丢失、能随时重建的统计缓存表。
-- 建一张内存表存点临时统计数据,重启就清空也不心疼
CREATE TABLE tmp_online_count (
room_id INT PRIMARY KEY,
online_num INT
) ENGINE=MEMORY;
不过说实话,这种场景现在大家更习惯直接丢给 Redis 处理,Memory 引擎的存在感是越来越低了。
其他还能见到的引擎
简单提一下,不展开讲,知道有这几个就够用了:
- Archive:只支持插入和查询,不支持更新删除,压缩率很高,适合日志归档这类只写不改的场景。
- CSV:直接把数据存成 CSV 文件格式,方便跟外部系统交换数据,性能和功能都很受限。
- NDB(MySQL Cluster):分布式集群方案专用引擎,一般公司用不上,除非上了 MySQL Cluster。
怎么切换/指定引擎
建表时指定:
CREATE TABLE mebugs_demo (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(64)
) ENGINE=InnoDB;
已有表想换引擎:
-- 把一张 MyISAM 的老表转成 InnoDB
ALTER TABLE old_myisam_table ENGINE=InnoDB;
这里要提一句:ALTER TABLE ... ENGINE= 在大表上执行代价不小,本质是重建整张表,会锁表一段时间(具体行为跟 MySQL 版本和 ALTER 算法有关)。
生产环境的大表迁移引擎,建议用 pt-online-schema-change 或者 gh-ost 这类工具做在线变更,别直接一条 ALTER 莽上去。
小结
说到底,现在建表基本不用纠结,InnoDB 打天下,事务、行锁、崩溃恢复它都占了,默认选它没错。
MyISAM、Memory 这些引擎不是没用,只是应用场景越来越窄,遇到老项目能看懂、能迁移就行,新项目基本不会主动选它们。
PS:不知道为什么,很多培训教程还在花大篇幅对比 MyISAM 和 InnoDB 的锁机制,但现实里 MyISAM 已经很少有人在新项目里用了,了解历史就好,别把重点搞偏了。
那存储引擎这块就先讲到这里,自行找张老表 SHOW TABLE STATUS 看一眼用的什么引擎吧。
