mysql要求auto_increment列必须是主键或唯一索引的第一列,否则建表或alter失败;该限制由server层强制执行,myisam与innodb在此规则上完全一致。

MyISAM 的 AUTO_INCREMENT 列不能作为复合索引第二列 —— 这个说法本身是错误的,MySQL 会直接拒绝建表或 ALTER 操作。
MySQL 对 AUTO_INCREMENT 列的索引位置有硬性限制
无论存储引擎是 MyISAM 还是 InnoDB,MySQL 的 SQL 层(parser + DDL 验证)都强制要求:AUTO_INCREMENT 列必须是某个索引的**最左前缀列**(即第一列),否则建表或修改会失败。
这不是引擎行为差异,而是 MySQL Server 层的语法校验规则。你尝试以下语句就会立刻得到错误:
CREATE TABLE t_myisam ( tenant_id INT, id INT AUTO_INCREMENT, PRIMARY KEY (tenant_id, id) ) ENGINE=MyISAM;
执行后报错:ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key。
这个错误不是因为 MyISAM “不支持”,而是因为 (tenant_id, id) 这个联合主键中,id 不是第一列 —— MySQL 根本不给机会让 MyISAM 去处理它。
为什么有人误以为 MyISAM “可以”?
- 混淆了“索引存在”和“索引结构”:MyISAM 允许你在
AUTO_INCREMENT列上单独建一个UNIQUE索引(比如UNIQUE(id)),同时表还有另一个联合索引(如(tenant_id, id))。但此时起自增作用的仍是那个单列索引,不是联合索引。 - 把“非自增列在联合索引里”当成“自增列在第二位”:例如建表时写
PRIMARY KEY (id), KEY (tenant_id, id),看起来id出现在第二个索引的第二位,但它在第一个(也是生效的自增索引)中仍是第一列。 - 测试时用了旧版本或配置绕过(极少见):某些非常老的 MySQL 5.0 分支在特定 sql_mode 下可能未严格校验,但不可靠、不推荐、已废弃。
MyISAM 和 InnoDB 在 AUTO_INCREMENT 索引要求上完全一致
两者都要求:AUTO_INCREMENT 列必须属于且仅属于一个 key(PRIMARY KEY 或 UNIQUE),并且必须是该 key 的第一列。
区别只在锁机制和并发行为上(比如 MyISAM 是表级自增锁,InnoDB 是轻量 auto-inc lock),但索引结构约束由 Server 层统一 enforce。
如果你真需要按 tenant_id 分组生成连续 ID,AUTO_INCREMENT 不是解法 —— 它天生不支持分组递增。应改用应用层序列号、单独维护的序列表,或 INSERT ... SELECT MAX(id)+1 FROM t WHERE tenant_id=? + 事务+唯一约束兜底(注意并发冲突)。
最容易被忽略的一点:错误信息里说的 “must be defined as a key”,指的不是“加个索引就行”,而是“必须是某个 key 的首列”。哪怕你给 id 加了 INDEX(非 UNIQUE/PRIMARY),也照样失败。











