我有一个几乎在所有表中都使用GUID作为主键的应用程序,并且我已经读到在使用GUID作为主键时存在有关性能的问题。老实说,我还没有遇到任何问题,但是我将要启动一个新的应用程序,并且我仍然想将GUID用作主键,但是我正在考虑使用复合主键(GUID以及其他领域。)

我使用的是GUID,因为当您具有不同的环境(例如“生产”,“测试”和“开发”数据库)以及在不同环境之间迁移数据时,它们很容易管理。数据库。

我将使用Entity Framework 4.3,并且想要在将Guid插入数据库之前在应用程序代码中分配它。 (即,我不想让SQL生成Guid。)

创建基于GUID的主键的最佳实践是什么,以避免与这种方法相关的假定性能损失? br />

评论

这个问题是不应该的。如果您的PK是群集的,那么几乎每个插入都有可能导致页面拆分。在现代版本的SQL Server中,已使用NEWSEQUENTIALID()对其进行了“修复”,但是却失去了能够预先计算出它的好处。我强烈建议您阅读其他地方的GUID,因为这是一个太宽泛的问题,可能会引发一场持续数小时的宗教斗争。

我还要补充一句,“服务器”一词不明确,因为我想在服务器端分配Guid(不要让SQL创建GUID)。

这个问题与此“ sql-server-guid-sort-algorithm-why”的相似之处stackoverflow.com/questions/7810602/…

#1 楼

GUID似乎是您的主键的自然选择-如果确实需要,您可能会争辩说将其用于表的PRIMARY KEY。我强烈建议您不要使用GUID列作为群集键,默认情况下,SQL Server会使用该列,除非您明确告知不要这样做。 :


主键是一种逻辑结构-候选键之一,可唯一且可靠地标识表中的每一行。实际上,这可以是任何东西-INTGUID和字符串-选择最适合您的情况的东西。是与物理存储相关的事情,在这里,小的,稳定,不断增长的数据类型是您的最佳选择-INTBIGINT是默认选项。

默认情况下,SQL Server表上的主键也用作群集键-但这不是必须的!当将以前的基于GUID的主键/集群键分解为两个单独的键-GUID上的主(逻辑)键和单独的INT IDENTITY(1,1)列上的集群(排序)键时,我个人看到了巨大的性能提升。

正如索引皇后金伯利·特里普(Kimberly Tripp)和其他人已经说过很多次了,因为聚类密钥不是最优的,所以GUID并不是最佳的,因为它的随机性,将导致大量页面和是的,我知道-SQL Server 2005及更高版本中存在newsequentialid()-但这甚至不是真正且完全顺序的,因此也存在与GUID相同的问题-不太明显。

然后还有一个要考虑的问题:表上的集群键也将添加到表上每个非聚集索引的每个条目中,因此,您确实要确保它尽可能小。通常,具有2+十亿行的INT应该足以容纳绝大多数表-与作为集群键的GUID相比,您可以为磁盘和服务器内存节省数百兆的存储空间。

快速计算-使用INTGUID作为主键和群集键:


基表具有1'000'000行(3.8 MB与15.26 MB )
6个非聚集索引(22.89 MB和91.55 MB)

总计:25 MB和106 MB-只是在一个表上!多想一想-金伯利·特里普(Kimberly Tripp)的优秀著作-读它,再读一次,消化它!确实,这是SQL Server索引的福音。


GUID作为PRIMARY KEY和/或聚集键
聚集索引的争论还在继续
每个群集的键不断增加聚集索引辩论...........再次!
磁盘空间很便宜-这不是重点!

PS:当然,如果您只处理一个几百行或几千行-这些参数中的大多数对您没有太大影响。但是:如果进入数万或数十万行,或者开始数以百万计,那么这些要点就变得非常关键,也非常重要。

更新:如果您想拥有自己的PKGUID列作为主键(而不是集群键),另一列MYINTINT IDENTITY)作为集群键-使用此:
必须明确告诉PRIMARY KEY约束它是NONCLUSTERED(否则默认情况下将其创建为聚簇索引)-然后创建第二个索引,定义为CLUSTERED这将起作用-如果您需要对现有系统进行“重新设计”以提高性能,那么这是一个有效的选择。对于新系统,如果您是从头开始的,并且您不在复制场景中,那么我总是选择ID INT IDENTITY(1,1)作为我的集群主键-比其他任何东西都效率更高!

评论


这是一个很好的答案,我要提到的一件事是,在插入之前能够生成密钥通常很有用。使用“ newsequentialid()”可以帮助进行群集,但是这需要额外的SQL往返。因此,“代理键”方法的另一个好处是,您可以在客户端生成新的id,而不必担心索引碎片。

–安德鲁·塞肯(Andrew Theken)
2014年2月26日在15:15

我读这本书的方式是,既有非聚集的uniqueidentifier列又有int身份列,FK也应该是uniqueidentifier?如果这样做,您什么时候会真正直接使用身份列,或者您不会?

–pinkfloydx33
2014年11月1日12:50

毫无疑问,GUID现在应该用于联接还是int id?我的直觉告诉我应该使用GUID,但是我看不到使用int id的技术问题...

–尼古拉斯·贝利(Nicolas Belley)
15年6月27日在13:33

@marc_s,但是在复制方案中,如果int列是标识,那么我们不应该使用GUID,因为int列可以在设备之间重复吗?

–尼古拉斯·贝利(Nicolas Belley)
15年6月28日在11:51

@Kipei:主要问题是您拥有如此自然的价值的I-F-是的,您可以将其用作主键。但是:像DATETIME这样的值对于聚类键没有用,因为它们的精度仅为3.33ms,因此可以存在重复项。因此,在这种情况下,您*仍然需要一个INT IDENTITY-因此,我通常默认情况下使用它,因为从我20多年的经验中,几乎没有真正可用的自然键...

– marc_s
17年9月25日在13:27

#2 楼

自2005年以来,我一直将GUID用作PK。在这个分布式数据库世界中,这绝对是合并分布式数据的最佳方法。您可以解雇合并表,而不必担心合并表之间的整数匹配。 GUID联接可以轻松复制。

这是我使用GUID的设置:


PK = GUID。 GUID的索引类似于字符串,因此高行表(超过5000万条记录)可能需要表分区或其他性能技术。 SQL Server变得异常高效,因此对性能的关注越来越少。
PK Guid是非聚集索引。除非它是NewSequentialID,否则切勿对GUID进行索引。但是即使这样,服务器重新启动也会导致顺序上的重大中断。
将ClusterID Int添加到每个表中。这是对您的表进行排序的聚集索引。如果要获得最佳性能,请使用ClusterID概念作为主键并加入ClusterID。

这是我的电子邮件表...

CREATE TABLE [Core].[Email] (
    [EmailID]      UNIQUEIDENTIFIER CONSTRAINT [DF_Email_EmailID] DEFAULT (newsequentialid()) NOT NULL,        
    [EmailAddress] NVARCHAR (50)    CONSTRAINT [DF_Email_EmailAddress] DEFAULT ('') NOT NULL,        
    [CreatedDate]  DATETIME         CONSTRAINT [DF_Email_CreatedDate] DEFAULT (getutcdate()) NOT NULL,      
    [ClusterID] INT NOT NULL IDENTITY,
    CONSTRAINT [PK_Email] PRIMARY KEY NonCLUSTERED ([EmailID] ASC)
);
GO

CREATE UNIQUE CLUSTERED INDEX [IX_Email_ClusterID] ON [Core].[Email] ([ClusterID])
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_Email_EmailAddress] ON [Core].[Email] ([EmailAddress] Asc)


评论


您能解释一下PK_Email约束吗?为什么您使用... NonClustered(EmailID ASC)而不是... Nonclustered(ClusterID ASC)?

–菲尔
17年9月2日在15:47

你打赌索引发生了两件事:1.在ClusterID上集群-在磁盘上排序表(0%碎片)。 2.基于电子邮件ID的非群集-索引电子邮件ID字段以加快GUID ID查找。 GUID字段查找的行为类似于字符串,因此如果没有索引,则电子邮件ID查找将很慢。

– Robert J. Good
2017年9月3日在16:28



@ RobertJ.Good我已经看过讨论此方法的方法,即在群集上添加代理int密钥。但是我找不到任何地方可以显示通过使用堆使用代理键聚集索引而获得的性能提升。您是否有指向基准数据的链接?

–戴尔K
19年7月5日在2:55



@DaleBurrell,您好,聚簇索引是为了防止表碎片。随着表在磁盘上的顺序自然增长且碎片少,性能会提高。

– Robert J. Good
19年8月20日在20:10

@ RobertJ.Good这是一个Web应用程序吗?您在url / hrefs中使用什么? guid或int?

– dariol
19/12/5在9:34



#3 楼

我目前正在使用EF Core开发Web应用程序,这是我使用的模式:

我所有的类(表)以及一个int PK和FK。类型为Guid(由c#构造函数生成),上面带有非聚集索引。与Guids配合使用。

评论


您是否需要执行任何操作来将整数pK配置为群集(如数据注释),还是只是自动配置?

–王艾伦
18年8月2日在20:07

您为Guid one使用的物业名称是什么?

–错误的潘
19年5月9日在17:50

如果您在Controller中收到Guid,如果您不知道相关的int,如何访问它?您在Guid列中进行顺序搜索吗​​?

–塞萨尔·阿尔瓦拉多·迪亚兹(Cesar Alvarado Diaz)
8月19日20:40

#4 楼

如果您使用GUID作为主键并创建聚簇索引,那么我建议为其使用默认值NEWSEQUENTIALID()

评论


为什么要这么做?

–genuinefafa
5月17日19:26

#5 楼

该链接比我说的更好,可以帮助我做出决策。我通常选择int作为主键,除非我有特殊需要,并且我还让SQL Server自动生成/维护该字段,除非有特殊原因。实际上,需要根据您的特定应用确定性能问题。这里有许多因素在起作用,包括但不限于预期的数据库大小,正确的索引编制,有效的查询等等。尽管人们可能会不同意,但我认为在许多情况下您不会注意到这两种选择的不同,您应该选择更适合您的应用程序的内容,以及允许您更轻松,更快,更有效地开发的内容(如果您从未完成过该应用程序其余的有什么不同:)。 -for-my-primary-key.html

PS我不确定您为什么要使用复合PK或您认为可以给您带来什么好处。

评论


完全同意!!但这意味着,如果我将GUID用作PK或将GUID与其他字段组合的PK将是相同的权利?

– VAAA
2012年8月13日在16:24

PK(索引)将由两列组成,但是除非您出于某些业务特定的原因要这样做,否则似乎没有必要。

–马特
2012年8月13日16:29

顺便说一句,这个问题是目前最两极分化和争议最大的问题之一,因此很难获得答案,因为您将百分百满意。两种方法都需要权衡,所以祝您好运:)

–马特
2012年8月13日在16:43

#6 楼

在大多数情况下,不应将它用作表的主键,因为它确实会影响数据库的性能。
有关GUID对性能的影响的有用链接以及它是主键。 >

https://www.sqlskills.com/blogs/kimberly/disk-space-is-cheap/
https://www.sqlskills.com/blogs/kimberly/guids -作为主键和/或群集键/


#7 楼

拥有顺序ID可以使黑客或数据挖掘者更容易地破坏您的站点和数据。为网站选择PK时请记住这一点。

评论


您可以提供任何逻辑或证据来支持此主张吗?我正在努力查看顺序ID如何危害安全性。

– jonaglon
1月28日在10:03



当然,如果您知道ID号是整数,则可以猜测数据库中的顺序记录。因此,如果查询单个项目,则可以说下一个项目是pk +1。如果您具有随机GUIDS,它将不会遵循模式。除了您先前查询过的记录(而且知道PK)以外,几乎不可能查询其他记录。

–Zonus
1月28日15:29

如果黑客可以查询您的数据库,那么您已经受到了威胁,那么我将看不到顺序ID如何使情况变得更糟。

– jonaglon
1月29日9:37

如果用户可以将1012换成另一个数字并查看他们不应该看到的数据,那么就存在一个非常严重的安全问题,该问题不是由主键选择引起的,而是由主键选择引起的。我同意你的意思,谢谢你的解释。

– jonaglon
1月30日15:27

您可以使用GUID在网页上找到记录,而不是表的PK。在网站中使用查询参数不应定义如何构造数据库架构。 PK与UI或后端系统中的输入和参数无关。

– Panos Roditakis
1月30日21:37