应选够用且不浪费的类型:INT比BIGINT每索引页多存约50%项(1638 vs 1170),降低B+树深度与I/O;联合索引宜统一整型宽度,避免隐式转换致索引失效。

选 INT 还是 BIGINT 做主键或索引字段,直接影响 B+ 树索引的深度、内存占用和磁盘 I/O 效率——不是“越大越好”,而是“够用且不浪费”。
索引页能存多少条记录?INT 比 BIGINT 多存约 50%
MySQL 的 InnoDB 索引页默认 16KB。每个索引项包含键值 + 指针(6 字节),INT 键占 4 字节,BIGINT 占 8 字节。按最简情况估算(忽略页头、间隙链等):
-
INT:每页可存约16384 / (4 + 6) ≈ 1638条索引项 -
BIGINT:每页可存约16384 / (8 + 6) ≈ 1170条索引项
这意味着同样 1000 万行数据,BIGINT 主键的二级索引树会更深、叶子页更多,范围扫描时读取的页数可能多出 20%~30%。尤其在冷数据场景下,I/O 放大更明显。
联合索引中混用 INT 和 BIGINT 会悄悄拖慢查询
如果一个联合索引定义为 (status INT, created_at BIGINT),InnoDB 在构建索引项时,会把两个字段拼成固定长度结构。哪怕 status 只有 1 个字节有效值,它仍按 INT 的 4 字节对齐;而 created_at 强制占满 8 字节。结果就是单个索引项膨胀到 12 字节以上,进一步降低页利用率。
- 实际优化建议:联合索引里尽量统一整型宽度,比如全用
INT或全用UNSIGNED INT - 若必须存时间戳,优先考虑
INT UNSIGNED存秒级 UNIX 时间(范围到 2106 年),而非BIGINT存毫秒 - 不要因为“以后可能扩容”就提前把所有 ID 字段都设成
BIGINT——迁移成本远高于预估
AUTO_INCREMENT 字段用 BIGINT 不等于性能更好
很多人以为“主键自增必须用 BIGINT 才安全”,但这是误解。InnoDB 的 AUTO_INCREMENT 计数器本身是 64 位,无论字段类型是 INT 还是 BIGINT,它都支持溢出检测。真正卡住的是字段本身的取值范围:
-
INT UNSIGNED最大值是4294967295,约 42 亿,对大多数业务已足够(比如日均 10 万新增记录,撑 115 年) -
BIGINT虽然上限高,但一旦被用作二级索引字段(如user_id),就会把所有关联索引都拖胖 - 注意:如果表已有大量数据,后期从
INT改成BIGINT需要重建整张表,锁表时间长,不是 ALTER COLUMN 就能秒改的
最常被忽略的一点:索引字段类型和 JOIN / WHERE 条件中的参数类型必须严格一致。比如 WHERE user_id = ?,如果 user_id 是 INT,但应用层传了 long 类型(Java/Go 默认),MySQL 可能隐式转成 BIGINT,导致索引失效。查 EXPLAIN 时留意 type 是否为 ALL 或 range,以及 key_len 是否符合预期字节数。



















