数据库主键:该选 int 还是 bigint?一场关于“工程直觉”与“心智负担”的博弈

在设计数据库表结构时,主键(Primary Key)的选择往往是我们的“第一步”。很多开发者在此时会产生一个疑问:“我的表数据量预计也就几万条,甚至只是存几十行配置,有必要用 bigint 吗?统一用 int 是不是更省空间?”

今天,我们就来深度拆解这个看似微小、实则影响深远的工程决策。


1. 21 亿的“隐形炸弹”

很多人选择 int 的理由是:int 的最大值约为 21 亿 ($2^{31}-1$)。在大多数人的直觉里,这是一个天文数字,一辈子也用不完。

但现实往往是残酷的:

  • 业务增长的非线性:一个起初只打算存用户信息的表,可能因为后来引入了“用户行为日志”或者“第三方数据同步”,在短短几个月内就冲破了 21 亿的关口。
  • 历史教训:YouTube 曾经就因为视频点击量超过了 int 的上限,导致系统崩溃,最后不得不紧急迁移到 bigint

结论: 在大数据时代,21 亿不再是不可逾越的鸿沟。

2. “事后补救”的代价

如果你在数据量达到 20 亿时才意识到要改类型,你将面临数据库运维中最痛苦的时刻:在大表上执行 DDL(数据定义语言)操作。

  • 锁表风险:在旧版本的数据库中,修改字段类型需要重建整张表,这会导致业务长时间停机。
  • 迁移成本:即便使用 gh-ost 等在线变更工具,处理数十亿行数据的字段升级也需要耗费数天甚至数周的时间,且伴随着巨大的数据一致性风险。

与其在未来某个深夜加班修库,不如在建表的第一天多花 4 个字节。

3. 微观优化 vs. 宏观效率

有人会争论:配置表明明只有几百行,用 bigint 简直是浪费。

让我们算一笔账:

  • int4 字节bigint8 字节
  • 对于一张 1000 行的配置表,两者差距仅为 4 KB
  • 在当今内存以 GB 计、磁盘以 TB 计的服务器环境下,这 4 KB 的空间节省几乎无法带来任何性能提升。

相反,“统一规范”带来的收益远大于“按需分配”:

  1. 降低心智负担:开发者无需在每次建表时反复纠结。
  2. 代码一致性:后端代码中的 Entity 对象可以统一使用 Long 类型,避免在关联查询或接口对接时出现类型溢出或不匹配。
  3. 兼容分布式 ID:如果你未来需要引入雪花算法(Snowflake)等分布式 ID 生成器,bigint 是唯一的硬性要求。

4. 什么时候该选 int?

虽然我倾向于“无脑 bigint”,但在极少数场景下,int(甚至 smallint)仍有其价值:

  • 超大规模且索引密集的表:如果你有一张数百亿行的表,且表上有 10 个以上的二级索引。此时主键从 8 字节降为 4 字节,能显著缩小索引文件体积,提升 Buffer Pool 的命中率。
  • 严格定义的静态字典:比如“性别”、“省份编码”,这些数据量有物理上限,绝无可能突破千万级。

5. 最终建议:我们的工程哲学

在现代软件工程中,“可维护性”和“容错性”的权重通常高于“微小的空间优化”。

  • 如果是业务表(用户、订单、流水、日志):请务必使用 bigint unsigned
  • 如果是配置表(菜单、权限、系统参数):即便预计只有几百行,为了规范统一,也建议首选 bigint

总结一句话:不要为了节省那几块钱的硬盘空间,去埋下一个可能导致全线宕机的隐患。

艾林博客 - 技术分享、开发经验与AI探索的个人技术博客
艾林博客 - 技术分享、开发经验与AI探索的个人技术博客

延伸阅读:

PHP 项目中的<span class="text-primary">安全防护实战技巧</span> 案例分析
PHP 项目中的安全防护实战技巧

本文详细阐述了 PHP 项目中常见的安全威胁,并提供了具体的实战防护技巧,涵盖 SQL 注入、XSS 攻击、文件包含漏洞等多个方面,帮助 PHP 开发者构建安全可靠的应用程序。

后端 优化 安全 PHP

Valencio

/

2025-05-07

Laravel 路由缓存问题排查与解决方案 案例分析
Laravel 路由缓存问题排查与解决方案

本文讲述在 Laravel + PHP 项目中,使用 php artisan route:cache 缓存路由时部分路由丢失的问题,分析出因特定路由分组定义方式导致问题,给出正确的定义格式及多文件支持的示例,并总结相关建议。

框架 后端 PHP Laravel

Valencio

/

2025-03-06