What are the best practices for using a GUID as a primary key, specifically regarding performance?
我有一个应用程序在几乎所有的表中都使用guid作为主键,我已经了解到使用guid作为主键时存在性能问题。老实说,我没有看到任何问题,但我即将启动一个新的应用程序,我仍然想使用guid作为主键,但我正在考虑使用复合主键(guid和其他字段)。
我之所以使用guid,是因为当您拥有不同的环境(如"生产"、"测试"和"开发"数据库)以及数据库之间的迁移数据时,它们既美观又易于管理。
我将使用Entity Framework 4.3,在将其插入数据库之前,我想在应用程序代码中分配guid。(即,我不想让SQL生成guid)。
创建基于guid的主键的最佳实践是什么,以避免与此方法关联的假定性能命中?
guid似乎是您的主键的自然选择——如果您真的必须这样做,您可能会争论将它用于表的主键。我强烈建议不要使用guid列作为集群键,这是SQL Server默认情况下所做的,除非您明确告诉它不要这样做。
你真的需要把两个问题分开:
主键是一个逻辑结构——一个唯一可靠地标识表中每一行的候选键。这可以是任何东西,真的-一个
集群键(定义表中"集群索引"的一列或多列)-这是与物理存储相关的东西,在这里,一个小的、稳定的、不断增加的数据类型是您最好的选择-
默认情况下,SQL Server表上的主键也用作群集键-但不需要这样做!我个人在将以前基于guid的主键/聚集键分解为两个单独的键(guid上的主键(逻辑)键和单独的
正如索引女王金伯利·特里普(Kimberly Tripp)和其他人多次提到的那样,由于集群密钥不是最佳的,因此由于其随机性,它将导致大量的页面和索引碎片,并且性能普遍较差。
是的,我知道-在SQL Server 2005及更高版本中都有
然后还有一个问题需要考虑:表上的集群键也将添加到表上每个非集群索引的每个条目中,因此您真的希望确保它尽可能小。通常,具有20多亿行的
快速计算-使用
- 具有1000'000行的基表(3.8 MB与15.26 MB)
- 6个非聚集索引(22.89 MB对91.55 MB)
总共:25 MB对106 MB-这只是在一张桌子上!
再吃点思考的食物——金伯利·特里普的绝妙佳肴——再读一遍,再消化一遍!这是SQL Server索引的福音,真的。
- 作为主键和/或聚集键的guid
- 聚集索引争论仍在继续。
- 不断增加的聚集键-聚集索引辩论……….再次!
- 磁盘空间很便宜-这不是重点!
附言:当然,如果你只处理几百或几千行的话——这些论点中的大多数对你没有太大的影响。然而:如果你进入数万或数十万行,或者你开始数到上百万行,那么这些点就变得非常重要,并且非常重要。
更新:如果您想让您的
1 2 3 4 5 6 7 8 9 10 | CREATE TABLE dbo.MyTable (PKGUID UNIQUEIDENTIFIER NOT NULL, MyINT INT IDENTITY(1,1) NOT NULL, .... add more columns as needed ...... ) ALTER TABLE dbo.MyTable ADD CONSTRAINT PK_MyTable PRIMARY KEY NONCLUSTERED (PKGUID) CREATE UNIQUE CLUSTERED INDEX CIX_MyTable ON dbo.MyTable(MyINT) |
基本上:您只需要明确地告诉
这是可行的——如果您有一个需要为性能"重新设计"的现有系统,这是一个有效的选择。对于一个新的系统,如果您从头开始,而不是在复制场景中,那么我总是选择
我从2005年开始就用guid作为pks。在这个分布式数据库世界中,它绝对是合并分布式数据的最佳方法。您可以触发并忽略合并表,而不必担心跨合并表匹配的整数。guid连接可以毫无顾虑地复制。
这是我使用guid的设置:
PK=GUID。guid的索引类似于字符串,因此高行表(超过5000万条记录)可能需要表分区或其他性能技术。SQL Server正变得非常高效,因此性能问题越来越不适用。
pk guid是非聚集索引。除非guid是newsequentialid,否则不要对其进行群集索引。但即便如此,重新启动服务器也会导致订购出现重大中断。
将clusterid int添加到每个表中。这是排序表的聚集索引。
加入clusterids(int)更有效,但我使用了2000-3000万个记录表,所以加入guid不会明显影响性能。如果您希望获得最大的性能,请使用clusterid概念作为您的主键&join on clusterid。
这是我的电子邮箱…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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) |
我目前正在开发一个具有EF核心的Web应用程序,下面是我使用的模式:
我所有的类(表)和一个int-pk和fk。我有一个附加的列,其类型为guid(由C构造函数生成),上面有一个非聚集索引。
EF中表的所有联接都是通过int键管理的,而外部(控制器)的所有访问都是通过guid完成的。
这个解决方案不允许在URL上显示int键,而是使模型保持整洁和快速。
如果您使用guid作为主键并创建聚集索引,那么我建议使用newsequentialid()的默认值。
这个链接比我所能说的更好,也帮助了我的决策。我通常选择int作为主键,除非我有特定的不需要,而且我还允许SQL Server自动生成/维护此字段,除非我有特定的不需要。实际上,性能问题需要根据您的特定应用程序来确定。这里有许多因素在起作用,包括但不限于预期的数据库大小、正确的索引、有效的查询等等。尽管人们可能不同意,但我认为在许多情况下,你不会注意到任何一个选项的不同,你应该选择更适合你的应用程序的选项,以及哪些选项可以让你更容易、更快、更有效地开发(如果你从未完成应用程序,其他选项有什么不同:)。
https://web.archive.org/web/20120812080710/http://databases.aspfaq.com/database/what-should-i-choose-for-my-primary-key.html
另外,我不知道你为什么要使用复合pk,或者你相信它会给你带来什么好处。
拥有连续ID使黑客或数据挖掘者更容易破坏您的站点和数据。在为网站选择pk时,请记住这一点。
大多数情况下,它不应该用作表的主键,因为它确实会影响数据库的性能。有关guid对性能的影响以及作为主键的有用链接。