MyISAM在纯读场景下比InnoDB快,因其无事务开销、无行级锁、不写undo log,索引与数据分离且SELECT不加锁;但需确保无任何并发写、避免跨引擎JOIN、合理配置KEY_BUFFER_SIZE和DELAY_KEY_WRITE,并注意MySQL 8.0默认禁用及崩溃恢复缺陷。

MyISAM 为什么在纯读场景下比 InnoDB 快
因为 MyISAM 没有事务开销、不维护行级锁、不写 undo log,索引和数据分离结构也让顺序扫描更轻量。它用表级锁,但“只读”时根本不上锁——SELECT 不触发任何锁机制,连 LOCK TABLES 都不用。
实操建议:
- 确认业务真的没有并发写:哪怕每小时一次
INSERT或UPDATE,MyISAM 表就会被锁住,所有后续读请求排队 - 避免混合使用:如果同一个库中其他表用 InnoDB,而你单独切 MyISAM,要注意
JOIN跨引擎时无法用外键、事务不一致、甚至某些备份工具(如mysqldump --single-transaction)会失效 - MyISAM 的
KEY_BUFFER_SIZE是全局共享的,不是按表分配;调大它对读性能提升明显,但别超过物理内存的 25% —— 否则可能挤占 OS 文件缓存
MyISAM 的 READ CONCURRENT 是什么,什么时候能用
这是 MyISAM 少数支持“读写并发”的机制:在插入末尾(INSERT DELAYED 已废弃,现在靠这个)允许新记录追加,同时不影响已有 SELECT。但它只对 INSERT 有效,UPDATE 和 DELETE 依然会触发全表锁。
实操建议:
- 建表时显式启用:
CREATE TABLE t (...) ENGINE=MyISAM DELAY_KEY_WRITE=1;,其中DELAY_KEY_WRITE=1让索引更新延迟到关闭表时刷盘,进一步减少读阻塞 -
READ CONCURRENT只在INSERT不带WHERE、不涉及主键/唯一键冲突、且表无FULLTEXT索引时才生效 - MySQL 8.0 默认禁用 MyISAM,需确认
disabled_storage_engines配置里没把MyISAM列进去,否则建表直接报错Unknown storage engine 'MyISAM'
MyISAM 在高并发读下的真实瓶颈在哪
不是 CPU,也不是磁盘 I/O,而是表元数据访问竞争:每个 SELECT 都要读取 .MYI 文件头里的行数、索引统计等信息,高并发下这些小读操作在文件系统层形成热点。
实操建议:
- 关掉
table_open_cache过载保护:设为足够大(比如 4096),避免频繁打开/关闭.MYD/.MYI文件 - 禁用
have_query_cache(MySQL 5.7+ 已默认关)—— MyISAM 的查询缓存粒度太粗,一个INSERT就让整张表缓存失效,反而拖慢读响应 - 不要依赖
SELECT COUNT(*):MyISAM 虽然快,但结果是估算值(除非加SQL_NO_CACHE),且在大表上仍会扫索引;真要精确计数,不如用单独维护的计数器表
替代方案比硬扛 MyISAM 更值得考虑
MyISAM 缺少崩溃恢复能力,.MYD 文件损坏后只能靠 myisamchk 修复,而修复过程本身又需要独占锁 —— 正是读密集场景最不能接受的停机点。
实操建议:
- 用 InnoDB + 调优代替:设
innodb_buffer_pool_size足够大,关掉innodb_flush_log_at_trx_commit(仅限日志可丢场景),开启read_only=ON模式,InnoDB 的读性能差距会大幅缩小 - 静态数据走
ARCHIVE引擎:如果只是归档历史只读数据,ARCHIVE压缩率高、内存占用低,SELECT单线程但足够快 - 终极解法其实是分层:热数据放 Redis,温数据走 ClickHouse 或 Doris 做 OLAP 查询,MySQL 只留必要关系逻辑 —— MyISAM 再快,也快不过内存随机读
真正卡住的从来不是引擎选型,而是“以为只读,其实有隐式写”的误判,比如触发器、INSERT ... ON DUPLICATE KEY UPDATE、或者应用层没关掉的自动时间戳更新。











