Guid vs INT - 作为主键哪个更好?

Bru*_*oLM 135 performance sql-server primary-key uniqueidentifier

我一直在阅读使用或不使用Guid和的原因int

int更小、更快、更容易记住、保持时间顺序。至于Guid,我发现的唯一优点是它是独一无二的。在哪种情况下 aGuid会更好int,为什么?

从我所看到的,int除了数量限制之外没有任何缺陷,这在许多情况下是无关紧要的。

究竟为什么被Guid创造?我实际上认为它除了用作简单表的主键之外还有其他用途。(任何Guid用于某事的实际应用程序的示例?)

SQL Server 上的 ( Guid = UniqueIdentifier ) 类型

Cod*_*awk 120

这已在此处此处的Stack Overflow 中提出。

Jeff 的帖子解释了很多关于使用 GUID 的利弊。

###GUID 优点

  • 每个表、每个数据库和每个服务器都是唯一的
  • 允许轻松合并来自不同数据库的记录
  • 允许跨多个服务器轻松分发数据库
  • 您可以在任何地方生成 ID,而不必往返数据库,除非需要部分顺序性(即使用newsequentialid()
  • 大多数复制方案无论如何都需要 GUID 列

###GUID 缺点

  • 它比传统的 4 字节索引值大 4 倍;如果您不小心,这可能会对性能和存储产生严重影响
  • 调试麻烦 ( where userid='{BAE7DF4-DDF-3RG-5TY3E3RF456AS10}')
  • 生成的 GUID 应该是部分顺序的以获得最佳性能(例如,newsequentialid()在 SQL Server 2005+ 上)并启用聚集索引

如果您确定性能并且不打算复制或合并记录,则使用int,并将其设置为自动增量(SQL Server 中的标识种子)。

  • @Brann 理想情况下,您首先不会将 PK 值提供给最终用户。我知道这样做有点普遍,而且在我学会不这样做之前,我自己过去也这样做过。但是由于不应该这样做,因此更喜欢 INT 而不是 GUID 的特殊原因是无效的。 (42认同)
  • GUID 方法的另一个缺点是您不能将其用作最终用户的标识符。您真的希望您的用户通过电话告诉您他们对订单“BAE7DF4-DDF-3RG-5TY3E3RF456AS10”有问题吗?:) (31认同)
  • 顺序 guid 仅在 SQL 实例重新启动之前是顺序的。然后,由于根值的生成方式,第一个值很可能会低于前一个值,从而再次导致各种问题。 (10认同)
  • @ChadKuehn 选择“UNIQUEIDENTIFIER”而不是“INT”,因为“INT”有上限是相当糟糕的推理,因为无限虽然足够真实,但并不是_实际_好处。通过从下限(-21.4 亿)而不是 1 开始,您可以轻松地将“INT”的有效容量加倍。或者,如果整个 43 亿不够,那么从“BIGINT”开始与 GUID 的 16 个字节相比,它仍然只有 8 个字节,并且它是连续的。 (5认同)
  • 如果您不使用顺序 guid,并且您的主键是群集的(SQL Server 默认),那么您的所有数据插入将随机分散在整个表中,导致数据大量碎片化。那是假设数据通常以某种顺序插入,例如按时间顺序。 (3认同)

rmi*_*lle 27

我成功地使用了混合方法。表包含两个自动增量主键整数id列和一guid列。将guid根据需要全局唯一标识该行并且可以使用id可用于查询,排序和行的人的识别。

  • id 标识此表中的行。GUID(至少在理论上)在已知宇宙中的任何地方标识该行。在我的项目中,每个 Android 手机在本地 SQLite 数据库上都有一个结构相同的表副本。该行及其 GUID 均在 Android 上生成。然后,当 Android 同步到后端数据库时,将其本地行写入后端表,而不必担心与从任何其他 Android 移动设备创建的行发生冲突。 (7认同)
  • 如果 `id` 已经足以让人类识别一行,那么 GUID 会给出什么值? (3认同)
  • @MartinSmith 我自己也使用过这种方法,效果很好。GUID 只是一个备用键,带有非聚集索引,从应用程序传入,但仅驻留在主表中。所有相关表都通过`INT` PK 相关联。我觉得奇怪的是,这种方法并不常见,因为它是两全其美的。似乎大多数人只是喜欢用非常绝对的术语解决问题,没有意识到 PK 不需要是 GUID,以便应用程序仍然使用 GUID 来实现全局唯一性和/或可移植性。 (3认同)

TML*_*TML 22

如果您将数据与外部源同步,持久的 GUID 会好得多。我们使用 GUID 的一个快速示例是一种工具,它被发送给客户以抓取他们的网络并执行某些类别的自动发现,存储找到的记录,然后将所有客户记录集成到中央数据库中回到我们这边。如果我们使用整数,我们将有 7,398 个“1”,而且要跟踪哪个“1”是哪个会困难得多。


小智 10

使用自动增量 ID 可能会泄露有关您的业务活动的信息。如果您经营一家商店并使用order_id公开识别购买,那么任何人都可以通过简单的算法找出您每月的销售额。


Jef*_*den 7

我在这个线程上看到了很多关于随机 GUID 的典型答案以及像 NEWSEQUENTIALID() 这样的东西来拯救世界。是的,我确实同意任何形式的 GUID 都很大,但这实际上是它们唯一的问题。我会告诉你,随机 GUID 并不是“被证明”的那样的碎片问题。在可能是您见过的有关 SQL Server 的最异端的演示中,我证明随机 GUID 碎片实际上是一个由于测试不足和错误信息而长期存在的神话。事实证明他们不是问题……我们才是问题!

总结一下如何防止数百万个插入的 GUID 碎片......

  1. 由于分布均匀,当碎片达到大约 1% 时,您就处于表中几乎所有页面上同时发生大量碎片的边缘。当逻辑碎片超过 1% 时,您必须采取行动。

  2. 您需要采取的操作是在填充因子之上创建自由空间。这意味着您不能使用 REORGANIZE,因为它无法创建额外的页面来展开索引以使可用空间高于填充因子。事实上,重新组织压缩页面直至填充因子。换句话说,它会尽力在最坏的情况下删除尽可能多的可用空间。相反,您必须使用 REBUILD 来代替。

  3. 事实证明,由于压缩,REORGANIZE 实际上会导致碎片并使其永久化。事实证明,实际上最好不要做任何索引维护,而不是做错事,而 REORGANIZE 所做的索引压缩是完全错误的,因为它无法在填充因子之上创建可用空间来阻止碎片。如果您是 24/7 或使用标准版,无法进行在线重建,那么请等待维护期。

  4. 此外,REORGANIZE 被宣传为比 REBUILD 占用的资源少得多。实际上并非如此,尤其是当您降低填充因子以防止碎片(即使在非 GUID 索引上)时。

我同意,由于我们多年来所接受的教育,这一切似乎都是不可能的。这是我制作的演示文稿的最后一张幻灯片,显示了 GUID 聚集索引(参见图例)的一年历史,使用预排序 GUID 作为不断增加的基线,没有碎片,没有索引维护的随机 GUID,以及具有 3 种不同的随机 GUID以每天 10 万行的插入速率使用 1%“低阈值”重建的填充因子。

“公寓是几乎没有发生碎片的地方

下面的一张幻灯片显示了 REORGANIZE 对日志文件的影响有多么糟糕。红线是所谓的“最佳实践”线,图表最底部的小绿线是 1%“低阈值”重建线。

REORGANIZE 和“低阈值”REBUILD 之间的资源使用比较

如果您想观看演示,请观看以下视频,在该视频中,我打破了随机 GUID 碎片的神话,并浪费了所谓的“最佳实践”索引维护,世界上 98% 的人在过去 22 年里都犯了错误年。然后,还要了解有关索引维护的经验教训也适用于其他类型的索引。

这是视频链接。作为对那些戴着耳机的人的警告,他们在 15:00、30:15 和 45:25 时间戳插入了一些突然出现的响亮广告,以“支付账单”以维持 GROUPBY.org 的运行。

这是链接。

Black Arts Index 维护 1.2 - 指南与碎片


Kin*_*tor 5

rmir​​abelle 的答案就是我所做的。然而,对于较大规模的项目,有一个最终设计,两者都可以使用:

用途:按键映射表

TableA.ID 在数据库中本地用作主键以及用于 JOINing 的键。TableAMap.ID 与TableA.ID 相同,TableAMap.UniversalID 仅用于系统之间。

TableA

- ID int (PK)
- Data varchar(100)

TableAMap

- ID int (PK)
- UniversalID GUID (Indexed - nonclustered)

Run Code Online (Sandbox Code Playgroud)

数据库复制/导入/导出很少需要 GUID。因此,不再将 GUID 放在主表上,因为它每行占用额外的 8 个字节,并且 GUID 索引将(默认情况下)存储在同一卷上;一个单独的表(又名标准化)可以解决这个问题。

有了单独的表,您的 DBA 就可以将其存储在另一个速度较慢的磁盘上。此外,如果仅某些批处理作业需要 GUID,您可以在需要之前创建 GUID 索引,然后将其删除。

另外,当然可以简单地将UniversalID 添加到TableA,而不是添加TableAMap 等扩展表。