【面试题】为什么建议 MySQL InnoDB 表建一个整型自增主键?
你如果不了解MySQL索引中数据的存储机制、查询过程和插入过程,请参考《浅析二叉树、B树、B+树、B*树和MySQL索引底层原理》,它介绍了二叉树、AVL树、红黑树、B树、B+树和B*树等六种树的数据结构后,浅析MySQL InnoDB索引选择B+树的原因,并给出一些 MySQL 索引高频面试题。这些知识点对回答上述问题非常非常重要,我简明扼要的归纳与本文密切相关的以下几点索引机制:
这样就会形成一个紧凑的索引结构,近似顺序填满,提升了数据页的最大填充率,不浪费数据页。由于新记录不需要为计算插入位置而做出额外的消耗,不需要移动已有数据或触发页分裂,也不需要增加很多开销在维护索引上,因此大幅提高写入效率。如果使用非自增主键,由于每次插入主键的位置近似于随机,使得MySQL不得不移动已有数据,甚至目标可能已经被回写到磁盘上而从缓存中清掉了,此时又要从磁盘上读回来,这增加了很多开销;同时频繁的移动记录、页分裂造成了大量的碎片,使得索引结构不够紧凑,后续不得不通过 OPTIMIZE TABLE来重建表,从而消除碎片、回收空间,并让数据页的填充更高效。
保持数据有序,优化查询性能。自增主键的有序性使得B+ 树支持高效的区间扫描(如 WHERE id > 1000 and id < 1100),即从根节点找到满足条件的第一个叶子节点后,无需再遍历内部节点,直接使用叶子节点之间的链接遍历相邻的叶子节点,并提取出在查询范围内的键值对,直到完成区间扫描。
简化系统设计,增强可维护性。自增主键由数据库自动生成,与业务逻辑解耦,避免因业务字段变更(如邮箱、手机号)导致主键更新的高成本操作。确保唯一性与非空性。主键天然保证每行数据唯一且非空,自增机制进一步自动化该过程,降低应用层复杂度。
引申一下,主键一定需要自增吗?答案是不。我们都知道在分布式系统或者分库分表时,自增主键就显得捉襟见肘不适用了。比如把订单表分成16个表,如果都使用自增ID的话,肯定会造成订单id重复,所以此时的解决方案就是分布式id(如雪花算法、美团Leaf、Redis生成ID等),保证趋势递增即可。
总之,不应该使用一个具有业务含义的列作为主键,并且一个表必须有一个整型自增主键,为方便扩展、松耦合、高可用的系统做铺垫。
自增主键的缺点