InnoDB主键查询一次IO即可获取整行数据,因其主键索引即聚簇索引,叶子节点直接存储整行记录;MyISAM所有索引均为非聚簇索引,主键查询需先查索引再按物理偏移量寻址,本质是两次独立磁盘访问。

主键查询时InnoDB一次IO就能拿到整行数据
InnoDB的主键索引就是聚簇索引,PRIMARY KEY对应的B+树叶子节点里直接存着整行记录。执行SELECT * FROM t WHERE id = 123时,InnoDB只用一次B+树查找就定位到目标页,数据就在那页里——不用跳转、不需额外寻址。
MyISAM所有索引(包括主键)都是非聚簇索引,叶子节点只存.MYD文件里的物理偏移量。哪怕按主键查,也得先读索引拿到地址,再用fseek去数据文件里找一次。这本质是两次独立磁盘访问,中间没有数据局部性可言。
聚簇索引让相邻主键的数据大概率物理相邻
InnoDB强制按主键顺序组织数据页,所以id在100–200范围内的记录,极可能落在连续或邻近的几个16KB页里。Buffer Pool缓存这些页后,后续点查或小范围扫描命中率高,随机IO少。
MyISAM的数据文件.MYD本身无序,即使id是自增的,插入过程中因删除、碎片、导入导出等操作,物理位置很快离散。查id IN (101,102,103)可能对应三个完全不相干的磁盘块,系统page cache利用率低,SSD上也难发挥局部性优势。
- MyISAM没全局行数缓存,
SELECT COUNT(*)必须扫全表或采样 - InnoDB的
buffer_pool缓存的是页,而MyISAM只靠key_buffer_size缓索引,数据靠OS page cache,稳定性差 - MyISAM表导出再导入后,
.MYD顺序丢失,SELECT * LIMIT 10结果可能每次都不一样
隐藏主键会破坏局部性,但MyISAM压根不关心这个
InnoDB表没显式PRIMARY KEY时,会偷偷加一个6字节隐藏_rowid作为聚簇索引键。这个_rowid是全局共享、带互斥锁的计数器,高并发插入容易锁争用,更关键的是:它生成的值不保证单调递增,导致新数据写入位置跳跃,页分裂频繁,物理存储碎片化严重。
MyISAM完全不依赖主键,插入就是追加到.MYD末尾,索引只更新指针。有没有主键、是不是自增,对它的物理布局和缓存友好度毫无影响。
迁移到InnoDB前若没补PRIMARY KEY,等于把局部性隐患打包带走——尤其当业务有大量WHERE id = ?查询时,性能落差会在高并发下迅速暴露。


















