当前位置: 首页 > 知识库问答 >
问题:

使用GUID作为主键的最佳实践是什么,特别是在性能方面?[闭门]

刘兴修
2023-03-14

原始关闭原因未解决

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

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

我将使用Entity Framework 4.3,在将Guid插入数据库之前,我希望在应用程序代码中分配Guid。(也就是说,我不想让SQL生成Guid)。

创建基于GUID的主键的最佳实践是什么,以避免与此方法相关的假定性能影响?

共有3个答案

百里修真
2023-03-14

我目前正在使用EF Core开发一个web应用程序,以下是我使用的模式:

我所有的类(表)都有intPK和FK。然后,我有一个类型为Guid(由C#构造函数生成)的附加列,其上有一个非聚集索引

EF中所有表的连接都是通过int键管理的,而外部(控制器)的所有访问都是通过Guids完成的。

此解决方案允许不在URL上显示int键,但保持模型整洁快速。

贝洲
2023-03-14

自2005年以来,我一直使用guid作为PKs。在这个分布式数据库世界中,这绝对是合并分布式数据的最佳方式。您可以触发并忘记合并表,而不必担心在连接的表之间进行int匹配。guid连接可以被复制而不必担心。

这是我使用guid的设置:

>

  • PK=GUID。GUID的索引类似于字符串,因此高行表(超过5000万记录)可能需要表分区或其他性能技术。SQL服务器变得非常高效,因此性能问题越来越不适用。

    PK Guid是非聚集索引。除非GUID是NewSequentialID,否则不要对其进行群集索引。但即便如此,重新启动服务器也会导致订单中断。

    将ClusterID Int添加到每个表中。这是您的CLUSTERED索引...

    加入ClusterIDs(int)更有效率,但我使用的是203000万的记录表,所以加入GUID不会明显影响性能。如果您想要最大的性能,请使用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)
    

  • 潘安邦
    2023-03-14

    对于主键来说,guid似乎是一个自然的选择——如果真的必须这样做,那么您可能会争论将其用于表的主键。我强烈建议不要使用GUID列作为集群键,SQL Server默认情况下会这样做,除非您明确告诉它不要这样做。

    你真的需要区分两个问题:

    >

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

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

    正如索引女王金伯利·特里普和其他人多次指出的那样,GUID作为集群键并不是最佳的,因为由于其随机性,它会导致大量的页面和索引碎片,并导致通常糟糕的性能。

    是的,我知道-在SQL Server 2005和更高版本中有newsequentialid(),但即使是这样,也不是真正的、完全顺序的,因此也会遇到与GUID相同的问题-只是不太明显而已。

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

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

    • 包含1'000'000行的基表(3.8MB对15.26MB)

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

    更多值得思考的东西——金伯利·特里普的优秀作品——读一读,再读一遍,消化它!这是SQL服务器索引福音,真的。

    • 作为主键和/或聚集键的GUID

    PS:当然,如果你处理的只是几百行或几千行,那么这些争论中的大多数都不会对你产生太大影响。然而,如果你进入数万或数十万行,或者你开始以百万计,那么这些点就变得非常关键,非常重要。

    更新:如果希望将PKGUID列作为主键(但不是群集键),另一列MYINTINT-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)
    

    基本上:你只需要明确地告诉主键约束它是非聚集的(否则默认情况下它被创建为你的聚集索引),然后你创建第二个定义为聚集的索引

    这将起作用——如果您有一个需要“重新设计”以提高性能的现有系统,这是一个有效的选择。对于一个新系统,如果你从零开始,而不是在一个复制场景中,那么我总是选择ID INT-IDENTITY(1,1)作为我的集群主键——比其他任何东西都要高效!

     类似资料:
    • 我有一个在几乎所有表中使用GUID作为主键的应用程序,并且我读到使用GUID作为主键时存在性能问题。老实说,我没有看到任何问题,但我即将启动一个新的应用程序,我仍然希望使用GUID作为主键,但我想使用一个复合主键(GUID和另一个字段) 我之所以使用GUID,是因为当您有不同的环境(如“Production”、“Test”和“Dev”数据库)时,以及在数据库之间迁移数据时,它们很好并且易于管理。

    • 问题内容: 我刚开始学习Go,并通读现有代码以学习“其他人的做法”。在这种情况下,遍历使用go“工作区”,尤其是与项目依赖关系有关的地方。 在处理各种Go项目时,使用一个或多个Go工作区(即$ GOPATH的定义)的常见(或存在)最佳实践是什么?我应该期望有一个类似于我所有项目的中央代码存储库的Go工作区,还是在我处理这些项目时都明确将其分解并设置$ GOPATH(有点像python) virtu

    • 问题内容: 我在某处读到,使用如下所示的类实例不是一个好主意,因为它们可能会导致内存泄漏。有人可以告诉我这是否是有效的声明?还是他们用这种方式有问题吗? 问题答案: 是的,您必须要小心!例如,如果您的代码在Web容器中运行,并且习惯于热部署Web应用程序,则对单个类对象的保留引用可能会导致大量Permgen内存泄漏。 本文详细解释了该问题。简而言之,问题在于每个类都包含对其类加载器的引用,而每个类

    • 问题内容: 我将开始使用AngularJS进行客户端和Django进行服务器端项目。 使他们像最好的朋友一样工作的最佳实践是什么(静态文件,身份验证,部署等) 问题答案: 有多种方法可以从Django模板中为客户端模板提供支持,以实现有趣的优化。但是,鉴于Django和AngularJS的模板语言之间的相似之处,在这里几乎不值得付出任何努力。对于此类大多数项目,我会将AngularJS的静态服务与

    • 想要改进此问题?通过编辑此帖子,更新问题,以便可以用事实和引文来回答问题。 原始关闭原因未解决 在 Flutter 中创建常量类以保留所有应用程序常量以便于参考的最佳编程实践是什么? 我知道Dart中有< code>const关键字用于创建常量字段,但是可以将< code>static与< code>const一起使用吗,还是会在运行时产生内存问题。

    • 那么使用clientResponse()的最佳实践是什么?如果唯一的问题是应用程序不知道何时应该关闭连接,.exchange().block()会自动关闭连接吗?如果我应该使用.close()-我应该如何获得这个方法?也许我应该使用另一个版本的spring-webflux?或者也许还有另一种在Spring中检索响应主体和状态的最佳方法--WebFlux?