关于sql server:使用GUID作为主键的最佳做法是什么,特别是关于性能?

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默认情况下所做的,除非您明确告诉它不要这样做。

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

  • 主键是一个逻辑结构——一个唯一可靠地标识表中每一行的候选键。这可以是任何东西,真的-一个INT,一个GUID,一个字符串选择什么对您的场景最有意义。

  • 集群键(定义表中"集群索引"的一列或多列)-这是与物理存储相关的东西,在这里,一个小的、稳定的、不断增加的数据类型是您最好的选择-INTBIGINT作为您的默认选项。

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

    正如索引女王金伯利·特里普(Kimberly Tripp)和其他人多次提到的那样,由于集群密钥不是最佳的,因此由于其随机性,它将导致大量的页面和索引碎片,并且性能普遍较差。

    是的,我知道-在SQL Server 2005及更高版本中都有newsequentialid(),但即便如此,它也不是真正完全连续的,因此也会遇到与GUID相同的问题-只是稍微不那么突出。

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

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

    • 具有1000'000行的基表(3.8 MB与15.26 MB)
    • 6个非聚集索引(22.89 MB对91.55 MB)

    总共:25 MB对106 MB-这只是在一张桌子上!

    再吃点思考的食物——金伯利·特里普的绝妙佳肴——再读一遍,再消化一遍!这是SQL Server索引的福音,真的。

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

    附言:当然,如果你只处理几百或几千行的话——这些论点中的大多数对你没有太大的影响。然而:如果你进入数万或数十万行,或者你开始数到上百万行,那么这些点就变得非常重要,并且非常重要。

    更新:如果您想让您的PKGUID列作为您的主密钥(而不是集群密钥),而另一列MYINT列(INT IDENTITY)作为您的集群密钥,请使用:

    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)

    基本上:您只需要明确地告诉PRIMARY KEY约束它是NONCLUSTERED(否则它默认创建为聚集索引),然后创建第二个定义为CLUSTERED的索引。

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


    我从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对性能的影响以及作为主键的有用链接。

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