【问题标题】:Using INT or GUID as primary key使用 INT 或 GUID 作为主键
【发布时间】:2014-02-20 02:20:12
【问题描述】:

我试图在 SQL 服务器 VB.net 中创建一个 ID 列,该列将为数据库中创建的每个新行提供一个数字序列。所以我使用以下技术来创建 ID 列。

select * from T_Users
ALTER TABLE T_Users     
ADD User_ID INT NOT NULL IDENTITY(1,1) Primary Key

然后我在数据库中注册了几个用户名,它工作得很好。例如,前六行将是 1,2,3,4,5,6。然后我第二天又注册了4个用户,但是这次ID号从6跳到了一个非常大的数字,例如:1,2,3,4,5,6,1002,1003,1004,1005。两天后,我又注册了两个用户,新行显示为 3002,3004。所以我的问题是为什么每隔一天我注册用户就会跳过这么多的数字。我用来创建序列的技术是否错误?如果错了,谁能告诉我如何做对吗?现在,当我对上面使用的技术感到沮丧时,或者我尝试使用顺序生成的 GUID 值。 GUID 值的序列生成良好。但是,唯一的缺点是,它会生成一个非常长的数字(INT 大小的 4 倍)。我的问题是使用 GUID 是否比 INT 有任何显着优势?

问候,

【问题讨论】:

    标签: sql-server vb.net


    【解决方案1】:

    GUID 的优势:

    如果您希望离线客户端能够创建新记录,则 GUID 非常有用,因为当新记录同步回主数据库时,您将永远不会遇到主键冲突。

    GUID 的缺点:

    作为主键的 GUIDS 会对数据库的性能产生影响,因为对于集群主键,数据库会希望按照键值的顺序保持行。但这意味着在现有记录之间进行大量插入,因为 GUID 将是随机的。

    使用 IDENTITY 列不会受到此影响,因为保证下一条记录具有最高值,因此每次都将行添加到末尾。无需重新洗牌。

    有一个折衷方案是生成一个伪 GUID,这意味着您预计每 70 年左右就会发生一次密钥冲突,但对索引编制有很大帮助。

    其他缺点是 a) 它们确实占用了更多存储空间,b) 编写 SQL 确实很痛苦,即输入 UPDATE TABLE SET FIELD = 'value' where KEY = 50003 比输入 UPDATE TABLE SET FIELD = 'value' where KEY = '{F820094C-A2A2-49cb-BDA7-549543BB4B2C}' 容易得多

    您对 IDENTITY 列的声明对我来说看起来不错。您的键值中的差距可能是由于尝试添加行失败。 IDENTITY 值将增加,但该行永远不会被提交。不要让它打扰你,它几乎发生在每张桌子上。

    编辑:

    这个问题涵盖了我所说的伪 GUID 的含义。 INSERTs with sequential GUID key on clustered index not significantly faster

    在 SQL Server 2005+ 中,您可以使用 NEWSEQUENTIALID() 来获取应该大于之前的随机值。请参阅此处了解更多信息http://technet.microsoft.com/en-us/library/ms189786%28v=sql.90%29.aspx

    【讨论】:

    • PK 的诀窍不是将它聚集在一起,而是聚集在具有逻辑顺序的东西上——例如日期戳、名称或其他任何东西。
    • DeanOC,感谢您的反馈。这很有帮助。
    【解决方案2】:

    我用来创建序列的技术是否错误?

    没有。如果有什么你的谷歌技能不存在。对“Sql server identity skipping values”的简短查找将为您提供大量回报,包括:

    SQL Server 2012 column identity increment jumping from 6 to 1000+ on 7th entry

    和规范:

    Why are there gaps in my IDENTITY column values?

    您基本上错误地认为 sql server 不会优化它的访问性能。身份证号码是标记,仅此而已,请不要假设没有空白。

    特别是:SQL Server 预先分配 1000 个块中的数字,并且 - 如果您重新启动服务器(如在您的工作站上),其余部分将丢失。

    http://www.sqlserver-training.com/sequence-breaks-gap-in-numbers-after-restart-sql-server-gap-between-numbers-after-restarting-server/-

    如果您改为手动执行 sqyuence(新的 nin sql server 2012),您可以为此定义缓存大小(预生成)并将其设置为 1 - 以执行大量插入时性能稍低为代价。

    我的问题是使用 GUID 是否比 INT 有任何显着优势?

    是的。使用 GUID 的行比使用 int 的行多得多。例如,int32 限制为大约 20 亿行。对于我们中的一些人来说,这太低了(我有 100 亿范围内的表),甚至 64 大的 int 也是有限的。而一个真正的 zetabyte 数据库,您必须按顺序使用 guid,自行生成。

    任何正常人都看不到差异,因为我们都没有真正处理那么多行。更大的尺寸会使很多事情变慢(更大的键大小=索引中的更大空间=更大的索引=更多的内存/同一操作的io)。另外,即使您的顺序 ID 也会跳跃。

    为什么不将您的期望调整为现实 - 身份并不意味着没有间隙 - 或者使用缓存 1 的序列。

    【讨论】:

    • 简单,杀手!还有比这更糟糕的问题。 ;)
    • 嗨 TomTom,首先让我对您的反馈表示感谢。在我读到一半之后,我对你描述你的想法的方式有点紧张,几乎想停止阅读。相信我,我使用 Google 是为了得到一个好的答案,但如果你没有在 Google 中写下正确的单词,你并不总能找到你正在寻找的答案。所以这不像我没有谷歌。因此,有时我们如何回答问题可能会阻止人们提出问题,这违背了拥有像 stackoverflow 这样的网站的目的。无论如何感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多