在 SQL 服务器中使用 Sequential Guid 作为主键会导致大数据性能低下吗?

Could using Sequential Guid as primary key in SQL Server lead to low performance for big data?

我使用过的最大的数据库是 SQL 服务器数据库,其中一个表包含 200,000 行。我使用 Guid 作为该数据库中的主键,而不是顺序 guid。我在那个有大约 30 个并发用户的系统中没有遇到任何性能问题。

最近设计开发了一个企业应用开发框架。为了利用 "Unit of Work" 模式,我使用了一个顺序 guid 作为主键,这样记录就会按物理顺序排列。由于我在大型数据库方面的经验仅限于我刚才提到的内容,我非常担心我是否要使用此框架为拥有 1000 个并发用户并保留数百万条记录的大型组织开发企业应用程序使用顺序 guid 作为主键的数据会导致性能问题吗?

如果是,程度如何?如果是,是否可以通过改进数据库服务器硬件(处理器和 RAM)来解决,然后再改进到什么程度?

提前感谢您分享您的经验和知识

GUID 似乎是您的主键的自然选择 - 如果您真的必须,您可能会争辩说将它用作 table 的主键。我强烈建议不要做的是使用GUID列作为集群键,SQL服务器默认情况下,除非你明确告诉它不要。

您确实需要将两个问题分开:

  1. 主键 是一种逻辑构造 - 唯一可靠地标识 table 中每一行的候选键之一。这可以是任何东西,真的 - INTGUID、字符串 - 选择对你的场景最有意义的东西。

  2. 集群键(在table上定义"clustered index"的一列或多列)-这是一个physical 存储相关的东西,在这里,一个小的,stable,不断增加的数据类型是你最好的选择 - INTBIGINT 作为你的默认选项。

默认情况下,SQL 服务器 table 上的主键也用作集群键 - 但不需要那样做!当将以前基于 GUID 的主键/集群键分解为两个单独的键时,我个人看到了巨大的性能提升 - GUID 上的主(逻辑)键和单独的 [ 上的集群(排序)键=17=]栏目。

作为 Kimberly Tripp - 索引女王 - 其他人已经多次声明 - GUID 因为聚类键不是最佳的, 因为由于它的随机性,它会导致大量的页面和索引碎片以及普遍糟糕的性能。

是的,我知道 - SQL Server 2005 及更高版本中有 newsequentialid() - 但即便如此也不是真正和完全顺序的,因此也遇到与 GUID - 只是稍微不那么突出。

然后还有另一个问题需要考虑:table 上的聚簇键也将添加到 table 上每个非聚簇索引的每个条目中 - 因此您真的想确保它尽可能小。通常,具有 2+ 十亿行的 INT 应该足以满足绝大多数 table 的需求 - 与 GUID 作为聚类键相比,您可以为自己节省数百兆字节的数据存储在磁盘和服务器内存中。

快速计算 - 使用 INTGUID 作为主键和聚类键:

  • 基础 Table 有 1'000'000 行(3.8 MB 对比 15.26 MB)
  • 6 个非聚集索引(22.89 MB 与 91.55 MB)

总计:25 MB 与 106 MB - 这只是一个 table!

是的 - 更大的 table 或索引自动意味着更多的数据页需要从磁盘加载、保存在内存中、传输到客户端 - 所有这些都会对您的性能产​​生负面影响。 有多少 影响实际上取决于您的数据库设计和数据分布的许多因素,因此任何广义预测几乎是不可能的...

还有一些值得深思的东西 - 金伯利·特里普 (Kimberly Tripp) 的优秀作品 - 读一遍,再读一遍,消化它!这是 SQL 服务器索引福音,真的。

顺序 GUID 与 "regular" GUID 的问题出现在以下情况中:

  • GUID 列是主索引或聚集索引的一部分(尤其是索引中的唯一键)。
  • 您的数据库有 "lots" 个插入。

对于聚簇索引,SQL 服务器将新记录添加到 table "in order"。因此,较大的值位于 table 的 "end" 处——在本例中,位于最后一个数据页上。这对于标识列很方便,因为它们保证比任何以前的值都大。根据定义,最后一个数据页没有碎片化。

GUID 没有这个 属性。它们最终被插入 "in the middle",导致碎片化。

为什么你不认为这是一个问题?可能有多种原因:

  • 您的应用程序没有进行很多插入。
  • 您正在定期对 table 进行碎片整理。
  • table 太小了,这几乎无关紧要。

至于后一点,如果记录足够小,那么每一页都能出现上千条。对于 200 页数据,碎片可能不是一个重要问题。

如果有 30 个并发用户,您可能根本没有事务重叠。如果每个用户每分钟修改一次数据库,那么您有 2 秒的时间来完成一个事务——通常足够的时间。

不过,我建议使用顺序 GUID 或标识列。这将使数据库保持清洁。但是,定期对数据库进行碎片整理是另一种可行的选择。