使用自定义编码方案作为主键而不是GUID

3
我正在将后端的 MS Access 数据库升级到 SQL Server。前端客户端暂时仍将保持为 Access 应用程序(有约 30k 行代码)。
目标是最终允许在多个服务器之间同步数据库(不使用复制,而可能使用同步框架)。 目前,Access 表中的所有主键都是自动递增整数代理。
我不是在询问升级过程,而是关于是否应该使用 GUID 或其他编码作为 PK(我知道可以在服务器之间分割数字范围,但我不想这样做,并且允许在必要时在客户端创建 PK,例如在离线模式下)。
GUID
优点: - 格式标准化。 - 确保唯一性(实际上是这样)。
缺点: - 在 Access 中不易操作,特别是当它们作为子窗体或控件的过滤器时。 - 由于随机性能降低插入性能。 - 具有多个表示形式:字符串、规范形式、二进制需要进行转换。
自定义编码方案
我认为使用更统一的代码作为 PK 的方案可能避免了性能惩罚,并且最重要的是确保 PK 在必要时仍可在表单控件中使用(并且不需要这些字符串之间的转换)。
我的编码方案的想法是一个由 10 个字符组成的代码,分为: - 8 位数字时间戳 - 4 位独特的客户端 ID - 2 位作为潜在冲突的随机数
每个数字都是基于 34 的,由 A-Z 和 2-9 的字母组成,避免了 O、0、1、I 的相似之处(以防需要手动处理这些 PK,例如在调试期间)。
优点: - 当必要时更容易手动处理。 - 不需要在不同表示之间进行转换,因为它基本上是一个字符串(因此需要适应的现有代码较少)。 - 确保唯一性(实际上)。
缺点: - JOIN 中的性能尚未得到证明。 - INSERT 中的性能应该比 GUID 更快,但尚未得到证明。 - 每个服务器/客户机必须设置自己的 UID,尽管这不应该是太大的问题。
所以,我应该使用 GUID 还是另一种方案作为我的 PK?

不想使用GUID作为主键/聚簇键,点个赞! - marc_s
我假设你已经阅读了http://trigeminal.com/usenet/usenet011.asp?1033,因为你知道Access中GUID问题的原因,但是我认为在这里加上一个评论,以便那些可能想知道为什么在Access中存在问题的细节的人。 - David-W-Fenton
@David:是的,还有很多其他问题。使用自定义代码而不是GUID的主要问题在于,在Jet中无法将用户定义函数作为默认字段值(除了一些内置函数)。因此,需要在代码/表单中初始化字段,并且我不喜欢将其用作PK。 - Renaud Bompuis
2个回答

3

在Access中不易操作,特别是在子表单或控件中使用它们作为过滤器时。

-> Access将GUID作为数字- >复制标识符。我们在Access中有一个应用程序,每个PK都是GUID,我们没有任何关于过滤器的问题(包括子表单和控件中的过滤器)。

由于其随机性会降低INSERT的性能。

-> 如果您基于此遇到性能问题,可以在另一列上添加聚集索引(例如时间戳)。但是MSSQL服务器有两个函数用于生成新的GUID值-"newid()"和"newsequenceid()"。第二种方法-正如名称所示-按顺序生成新值,因此插入性能问题不应该发生。

具有多个表示形式:字符串、规范形式、二进制需要转换。

-> 在我看来这是它的“PRO”:)。但是对于用户开发人员和用户管理员,在Access和MSSQL中表示和消耗为字符串。

GUID在核心中仅是128位数字。我认为您不必担心在GUID列上进行JOIN的效率。与文本列上的条件相比,连接GUID列要高效得多。

我不认为自定义编码方案是一个好主意,因为您必须解决许多问题。另一方面,GUID被标准使用,并且工具已准备好使用它。


你如何在Access应用程序中创建连续的GUID?我需要在客户端上保留此功能,以便我可以拥有离线模式,在该模式下客户端可能与SQL服务器断开连接。 - Renaud Bompuis
当你连接时,可以从 MSSQL 上的 Access 调用 "newsequenceid()" 函数。 但是,当你断开连接时,“newsequenceid()” 函数就无法使用了。但我真的认为,不按顺序的 ID 不是问题。我们多年来一直使用 GUID 作为主键,并没有性能问题。 - TcKs
GUIDs在聚集索引中是非常糟糕的选择(默认情况下,主键就是聚集索引)。它们会导致严重的碎片化问题,并且对性能造成全面的影响。此外,由于聚集键包含在每个非聚集键中,它们的大小(16字节对比4字节的INT)也是一个问题! - marc_s
在Access中使用GUID存在问题,可以在这里找到详细信息:http://trigeminal.com/usenet/usenet011.asp?1033。当然,有一些解决方法,但如果可能的话,我会避免在任何带有Access前端的应用程序中使用GUID。 - David-W-Fenton
@marc_c:就像我所写的那样-聚集索引可以是任何其他东西。在具有1,000,000条记录的表中,16B和4B之间的差异仅为8MB。 8MB的成本非常非常小。您指的问题是什么? - TcKs
@David W. Fenton:有趣。你应该阅读第17条:“你能依赖系统表吗……?”(http://trigeminal.com/usenet/usenet017.asp?1033):它解释了为什么ACE不是Jet(提示:因为一些针对Jet编写的代码被ACE破坏;如果ACE实际上是Jet 5.0,那么这是不允许的)。 - onedaywhen

2
你打算有多少条记录?bigint不够大吗?最多可以有9,223,372,036,854,775,807条记录(如果不包括负数)。
如果只是插入数据,而没有对数据进行选择,请使用任何方案(我仍然建议使用bigint或GUID/uniqueidentifier)。如果需要进行选择,则int或bigint比GUID或任何其他自定义主键快得多。

自增的问题在于,如果您希望应用程序脱机或跨多个服务器工作,它们很难管理。您需要分配范围,这不是我想要管理的事情,而且可能会变得非常麻烦。 - Renaud Bompuis
我倾向于同意TcKs的答案,我认为插入时的理论性能问题比使用标准内置数据类型的优点不那么重要,因为标准数据类型比任何自定义方案更易于使用和维护。 - Gideon
不要把 GUID 作为主键,确切地说是聚集键,因为这种设计非常糟糕!使用 GUID 作为聚集键不仅会降低插入性能,还会严重碎片化表格,导致整个性能下降。 - marc_s
请查看Kimberly Tripp在http://sqlskills.com/BLOGS/KIMBERLY/post/The-Clustered-Index-Debate-Continues.aspx上关于永无止境的聚集键辩论的优秀文章。 - marc_s
此外,Access 不识别 BIGINT。您必须采取解决方法才能使具有 BIGINT PK 的结果可编辑。 - David-W-Fenton
那么,如果BIGINT不行,GUID也不行,而我需要比标准longint更多的东西 - 我在使用SQL后端的Access前端应用程序时就没有办法了吗? - Comrad_Durandal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接