GUID做主键真的合适吗


  在一个分布式环境中,我们习惯使用GUID做主键,来保证全局唯一,然后,GUID做主键真的合适吗?

  其实GUID做主键本身没有问题,微软的很多项目自带DB都是使用GUID做主键的,显然,这样做是没有问题的。然而,SQL Server默认会将主键设置为聚集索引,使用GUID做聚集索引就有问题了。很多时候程序员容易接受SQL Server这一默认设置,但无序GUID做聚集索引显然是低效的。

  那么,我们在项目中如何避免这一问题呢?

  主要的思路还是两方面——方案一,选择合适的列作为聚集索引;方案二,使用有序的主键。

1 方案一,选择合适的列做聚集索引

  选择原则很简单——字段值尽量唯一,字段占用字节尽量小,字段值很少修改,字段多用于查询范围数据或排序的数据。

  之所以是根据以上原则选择,主要还是基于B+树数据索引问题,这部分内容都比较基础,这里就不举例验证了,以上原则还是比较公认的,即便读者不太理解其中原理,也请记住这一选择规则。

  常见的备选项——自增列(Id)和时间列(CreateTime)。

  聚集索引的最大用处就是帮助范围查询快速定位,从而减小数据库IO的消耗来提升查询效率。对于范围查询我们更多的应用在自增列和时间列上,因为这两列本身反应了数据的创建顺序,符合多数范围查询的场景需要。

  大部分时候,我们仍然可以使用GUID做主键,只需要重新设置聚集索引就行。

2 方案二,有序的主键

  对于一个分布式环境,保证唯一和有序性,实际上有多种方法,各有利弊。

2.1 分布式数据库

  对于分布式数据库,简单使用自增主键即可,比如Tidb。

  TiDB 中,自增列只保证自增且唯一,并不保证连续分配。TiDB 目前采用批量分配 ID 的方式,所以如果在多台 TiDB 上同时插入数据,分配的自增 ID 会不连续。TiDB 实现自增 ID 的原理是每个 tidb-server 实例缓存一段 ID 值用于分配(目前会缓存 30000 个 ID),用完这段值再去取下一段。

  优点:简单好用

  缺点:不能设置ID,需要使用数据库的;ID不保证连续分配,也无法根据ID来判断数据创建的先后;负载不均匀,有数据热点问题

2.2 基于Redis等中间件的

  根据数据库分片方式不同,又有两种情形。

  方式一,取模分片

  总之,GUID能满足大部分需要,但如果想要我们的程序精益求精,也可以考虑使用本文提到的方法,感谢阅读。