存储引擎决定事务能否存在,事务机制的开销是在存储引擎之上的——所以先选对存储引擎,再谈事务怎么用。InnoDB 支持事务,MyISAM 不支持;用 MyISAM 强行套事务逻辑,只会让
START TRANSACTION和
COMMIT变成无效空操作,还误以为自己“有事务保障”。
为什么 InnoDB 的事务开销比 MyISAM 高
InnoDB 在每次写操作中要维护:
redo log(保证崩溃恢复)、
undo log(支持回滚和 MVCC)、行级锁结构、聚簇索引组织方式。而 MyISAM 只做表级锁 + 简单的磁盘文件追加。 一个
UPDATE在 InnoDB 中可能触发:索引页分裂、缓冲池刷脏、日志刷盘、锁等待检测 同样语句在 MyISAM 中只是:获取表锁 → 修改 .MYD 文件 → 释放锁 高并发写场景下,InnoDB 的
innodb_flush_log_at_trx_commit设置会显著影响吞吐(设为 2 比 1 快 3–5 倍,但掉电可能丢 1s 日志)
事务隔离级别对性能的实际影响点
不是“级别越高越慢”,而是
READ COMMITTED和
REPEATABLE READ在 InnoDB 中实现方式不同,直接影响 undo log 保留时长和一致性读路径。
REPEATABLE READ下,事务启动时会固定一个
read view,后续所有
SELECT都基于它;长事务会让 undo log 无法清理,撑爆
ibdata1
READ COMMITTED每次
SELECT都新建 read view,避免长事务拖累,但频繁快照生成有轻微 CPU 开销
SERIALIZABLE会把普通
SELECT自动加上共享锁,极易引发锁等待,实际业务中极少使用
什么时候该怀疑是引擎/事务配置惹的祸
遇到这些现象,优先查存储引擎和事务相关配置,而不是一上来优化 SQL:
执行SHOW CREATE TABLE t1发现引擎是
MyISAM,但代码里写了
BEGIN; UPDATE; COMMIT;—— 这些事务控制完全没生效
SHOW ENGINE INNODB STATUS里反复出现
TRANSACTIONS区域的
lock wait timeout或大量
history list length> 10000
innodb_buffer_pool_size设得太小(比如仅 128M),又开着
autocommit=0批量导入,导致频繁刷脏和日志等待
真正卡顿往往不出现在 SQL 本身,而出现在引擎层对事务语义的兑现过程里——比如一个没提交的事务,正拿着 10 万行记录的 undo log 不放,别的查询就得绕着它走。这种问题不会报错,但会让响应时间飘忽不定。
