我有一个应用程序,在几乎所有的表中使用GUID作为主键,我读到使用GUID作为主键时存在性能问题。老实说,我还没有看到任何问题,但我要开始一个新的应用程序,我仍然想使用GUID为主键,但我在考虑使用一个复合主键(GUID和可能另一个字段)。

我之所以使用GUID,是因为当你有不同的环境,如“生产”、“测试”和“开发”数据库时,它们很好且易于管理,而且还用于在数据库之间迁移数据。

我将使用实体框架4.3,我想在应用程序代码中分配Guid,然后将其插入数据库。(例如,我不想让SQL生成Guid)。

为了避免与此方法相关的性能损失,创建基于gui的主键的最佳实践是什么?


当前回答

guid似乎是主键的自然选择——如果确实必须,可能会主张将它用于表的primary key。我强烈建议不要使用GUID列作为集群键,SQL Server默认是这样做的,除非您特别告诉它不要这样做。

你真的需要把两个问题分开:

主键是一个逻辑结构——唯一且可靠地标识表中的每一行的候选键之一。这可以是任何东西——一个INT,一个GUID,一个字符串——选择对你的场景最有意义的。 聚类键(在表上定义“聚类索引”的一列或多列)——这是一个与物理存储相关的东西,在这里,一个小的、稳定的、不断增长的数据类型是您的最佳选择——INT或BIGINT作为默认选项。

默认情况下,SQL Server表上的主键也被用作集群键——但这并不需要这样!我个人看到过将先前基于GUID的主键/集群键分解为两个单独的键——GUID上的主键(逻辑键)和单独的INT IDENTITY(1,1)列上的集群键(排序键)——获得了巨大的性能提升。

正如索引女王Kimberly Tripp和其他人多次指出的那样,将GUID作为聚类键并不是最优的,因为它的随机性,它将导致大量的页面和索引碎片,并且通常会导致糟糕的性能。

是的,我知道-在SQL Server 2005及更高版本中有newsequentialid() -但即使是它也不是真正的和完全的顺序的,因此也遭受与GUID相同的问题-只是没有那么突出。

然后还有另一个问题需要考虑:表上的聚类键也将被添加到表上的每个非聚类索引的每个条目中——因此您确实希望确保它尽可能小。通常,一个包含20多亿行的INT对于绝大多数表来说应该足够了——与GUID作为集群键相比,您可以在磁盘和服务器内存中节省数百兆字节的存储空间。

快速计算-使用INT vs. GUID为主键和聚类键:

1'000'000行基本表(3.8 MB vs. 15.26 MB) 6个非聚集索引(22.89 MB vs. 91.55 MB)

总计:25mb vs. 106mb——这只是在单个表上!

金伯利·特里普的精彩作品——再读一遍,消化它!它是SQL Server索引的福音,真的。

guid作为主键和/或聚集键 关于聚集指数的争论仍在继续 不断增加的聚类关键-聚类索引辩论..........再次! 磁盘空间很便宜——这不是重点!

PS:当然,如果你处理的只是几百行或几千行,大多数参数对你不会有太大的影响。然而,如果你进入数万或数十万行,或者你开始以数百万为单位计算,那么这些点就变得非常重要,非常重要。

更新:如果你想有你的PKGUID列作为你的主键(但不是你的聚类键),和另一个列MYINT (INT IDENTITY)作为你的聚类键-使用这个:

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)

基本上:你只需要显式地告诉PRIMARY KEY约束它是NONCLUSTERED(否则默认情况下它会被创建为你的聚集索引)——然后你创建第二个定义为clustered的索引

这是可行的——如果您的现有系统需要“重新设计”以提高性能,那么这是一个有效的选择。对于一个新系统,如果从头开始,并且不是在复制场景中,那么我总是选择ID INT IDENTITY(1,1)作为我的集群主键——这比其他任何方法都要高效得多!

其他回答

This link says it better than I could and helped in my decision making. I usually opt for an int as a primary key, unless I have a specific need not to and I also let SQL server auto-generate/maintain this field unless I have some specific reason not to. In reality, performance concerns need to be determined based on your specific app. There are many factors at play here including but not limited to expected db size, proper indexing, efficient querying, and more. Although people may disagree, I think in many scenarios you will not notice a difference with either option and you should choose what is more appropriate for your app and what allows you to develop easier, quicker, and more effectively (If you never complete the app what difference does the rest make :).

https://web.archive.org/web/20120812080710/http://databases.aspfaq.com/database/what-should-i-choose-for-my-primary-key.html

附注:我不确定你为什么要使用复合PK,或者你认为这会给你带来什么好处。

使用顺序ID会让黑客或数据挖掘者更容易破坏你的网站和数据。在为网站选择PK时,请记住这一点。

guid似乎是主键的自然选择——如果确实必须,可能会主张将它用于表的primary key。我强烈建议不要使用GUID列作为集群键,SQL Server默认是这样做的,除非您特别告诉它不要这样做。

你真的需要把两个问题分开:

主键是一个逻辑结构——唯一且可靠地标识表中的每一行的候选键之一。这可以是任何东西——一个INT,一个GUID,一个字符串——选择对你的场景最有意义的。 聚类键(在表上定义“聚类索引”的一列或多列)——这是一个与物理存储相关的东西,在这里,一个小的、稳定的、不断增长的数据类型是您的最佳选择——INT或BIGINT作为默认选项。

默认情况下,SQL Server表上的主键也被用作集群键——但这并不需要这样!我个人看到过将先前基于GUID的主键/集群键分解为两个单独的键——GUID上的主键(逻辑键)和单独的INT IDENTITY(1,1)列上的集群键(排序键)——获得了巨大的性能提升。

正如索引女王Kimberly Tripp和其他人多次指出的那样,将GUID作为聚类键并不是最优的,因为它的随机性,它将导致大量的页面和索引碎片,并且通常会导致糟糕的性能。

是的,我知道-在SQL Server 2005及更高版本中有newsequentialid() -但即使是它也不是真正的和完全的顺序的,因此也遭受与GUID相同的问题-只是没有那么突出。

然后还有另一个问题需要考虑:表上的聚类键也将被添加到表上的每个非聚类索引的每个条目中——因此您确实希望确保它尽可能小。通常,一个包含20多亿行的INT对于绝大多数表来说应该足够了——与GUID作为集群键相比,您可以在磁盘和服务器内存中节省数百兆字节的存储空间。

快速计算-使用INT vs. GUID为主键和聚类键:

1'000'000行基本表(3.8 MB vs. 15.26 MB) 6个非聚集索引(22.89 MB vs. 91.55 MB)

总计:25mb vs. 106mb——这只是在单个表上!

金伯利·特里普的精彩作品——再读一遍,消化它!它是SQL Server索引的福音,真的。

guid作为主键和/或聚集键 关于聚集指数的争论仍在继续 不断增加的聚类关键-聚类索引辩论..........再次! 磁盘空间很便宜——这不是重点!

PS:当然,如果你处理的只是几百行或几千行,大多数参数对你不会有太大的影响。然而,如果你进入数万或数十万行,或者你开始以数百万为单位计算,那么这些点就变得非常重要,非常重要。

更新:如果你想有你的PKGUID列作为你的主键(但不是你的聚类键),和另一个列MYINT (INT IDENTITY)作为你的聚类键-使用这个:

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)

基本上:你只需要显式地告诉PRIMARY KEY约束它是NONCLUSTERED(否则默认情况下它会被创建为你的聚集索引)——然后你创建第二个定义为clustered的索引

这是可行的——如果您的现有系统需要“重新设计”以提高性能,那么这是一个有效的选择。对于一个新系统,如果从头开始,并且不是在复制场景中,那么我总是选择ID INT IDENTITY(1,1)作为我的集群主键——这比其他任何方法都要高效得多!

不要在用户界面中公开Id的另一个原因是,竞争对手可以看到您的Id在一天或其他时间段内的增量,从而推断出您正在做的业务量。

大多数情况下,它不应该用作表的主键,因为它确实会影响数据库的性能。 关于GUID对性能的影响和作为主键的有用链接。

https://www.sqlskills.com/blogs/kimberly/disk-space-is-cheap/ https://www.sqlskills.com/blogs/kimberly/guids-as-primary-keys-andor-the-clustering-key/