为啥不推荐使用uuid作为Mysql数据库的主键呢
在mysql中设计表的时候,mysql官方并不推荐使用uuid或者不连续不重复的雪花id,而是推荐使用连续自增的主键id。
官方推荐的是auto_increment。主要原因是uuid在数据量较大的情况下,效率直线下滑。
使用uuid和自增id的索引结构对比
使用自增id的内部结构
自增的主键的值是顺序的,所以Innodb把每一条记录都存储在一条记录的后面。当达到页面的最大填充因子的时候(innodb是15/16)
下一条记录会写入新的页中,一旦数据按照这种顺序的方式加载,主键页就会近乎于顺序的记录填满,提升了页面的最大填充率,不会有页的浪费
新插入的行一定会在原有的最大数据行的下一行,mysql定位和寻址很快,不会为计算新行的位置而做出额外的消耗
减少了页分裂和碎片的产生
缺点
- 别人容易根据自增的id爬取数据库,从而分析数据
- 对于高并发的负载,innodb在按主键进行插入的时候会造成明显的锁争用,主键的上界会成为争抢的热点。因为所有的插入都发生在这里,并发插入会导致间隙锁竞争
- @Auto_Increment锁机制会造成自增锁的抢夺,有一定的性能损失
使用uuid的索引内部结构
因为uuid毫无规律可言,新值和旧值大小无法确定,所以需要innodb要为新行寻找新的合适的位置从而来分配新的空间。会导致以下几个问题:
- 写入的目标页很可能已经刷新到磁盘上并且从缓存上移除,或者还没有被加载到缓存中,innodb在插入之前不得不先找到并从磁盘读取目标页到内存中,这就导致了大量的随机IO
- 因为写入是乱序的,所以innodb不得不频繁的做页分裂操作,以便为新的行分配空间,页分裂导致移动大量的数据,一次插入最少修改三个页以上
- 由于频繁的页分裂,页会变得稀疏并被不规则的填充,最终会倒是数据有碎片
把随机值(uuid和雪花id)载入到聚簇索引(innodb默认的索引类型)以后,有时候会需要做一次OPTIMEIZE TABLE来重建表并优化页的填充,这将又需要一定的时间消耗。
总结:
使用innodb应该尽可能的按主键的自增顺序插入,并且尽可能使用单调的增加的聚簇键的值来插入新行