myisam 的 count(*) 是 o(1),因其直接读取 .myi 文件头的 rec_count 元数据,不扫描数据、不走索引、不判断可见性;但仅限无 where 条件的全表统计,且依赖表未崩溃、未重建、未重启等前提。

COUNT(*) 在 MyISAM 表上是 O(1),因为它根本没扫描数据。
MyISAM 把精确行数存在 .MYI 文件头固定偏移处,叫 rec_count。每次 INSERT 或 DELETE 都原子更新它。执行 SELECT COUNT(*) FROM t 时,MySQL 直接从这个元数据里取值,不读数据页、不走索引、不判断事务可见性。
- 这个值在表未崩溃、未被
ALTER TABLE重建、且服务器没重启过的情况下,是精确的 - 如果执行过
OPTIMIZE TABLE或 MySQL 刚启动,首次COUNT(*)可能触发一次全表扫描来重建rec_count -
COUNT(1)、COUNT(pk)、COUNT(*)在 MyISAM 下完全等价,执行计划和耗时一致 - 一旦加了
WHERE条件(哪怕WHERE 1),就立刻退化为实际索引扫描,O(1) 失效
EXPLAIN SELECT COUNT(*) FROM t 显示 type: ALL 或 type: index?说明你已经掉出 O(1) 路径了——那不是 MyISAM 的问题,是你写了条件。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
它快,只因为设计上放弃了事务、MVCC 和崩溃安全。
-
ENGINE=MyISAM必须显式指定,MySQL 5.7+ 默认建表是 InnoDB,用SHOW CREATE TABLE t确认 - 它不支持行锁,写操作会锁整张表;没有
DB_TRX_ID和DB_ROLL_PTR,自然不用做可见性判断 -
SHOW TABLE STATUS LIKE 't'返回的Rows字段在 MyISAM 下是精确值,但并发写入时可能短暂不一致(虽然概率低)
别拿 InnoDB 的优化思路套 MyISAM:加覆盖索引、调 innodb_stats_sample_pages、用 USE INDEX —— 全无效,它压根不走索引扫描。
真正容易被忽略的是:这个 O(1) 只存在于无条件全表统计这个狭窄场景;业务只要需要事务、任意 WHERE、或写一致性,MyISAM 就不再适用,而代价早在建表那一刻就已埋下。










