SQL Guid主键加入性能

时间:2013-11-29 14:20:49

标签: sql sql-server database-design azure-sql-database

我目前正在使用GUID作为NONCLUSTERED PRIMARY KEYINT IDENTITY列。

GUID必须允许脱机创建数据和同步 - 这就是整个数据库的填充方式。

我知道将GUID用作聚簇主键的含义,因此是整数聚簇索引但使用GUID作为主键,因此其他表上的外键具有显着的性能影响吗?

更好的选择是使用整数主/外键,并使用GUID作为每个表上有UNIQUE INDEX的客户端ID? - 我担心的是,实体框架需要加载导航属性才能获得相关实体的GUID,而无需对现有代码进行重大更改。

有问题的数据库/硬件是SQL Azure。

3 个答案:

答案 0 :(得分:4)

您还可以针对唯一键约束创建外键,然后为您提供ID身份的外键选项,作为Guid的替代。

Create Table SomeTable
(
    UUID UNIQUEIDENTIFIER NOT NULL,
    ID INT IDENTITY(1,1) NOT NULL,

    CONSTRAINT PK PRIMARY KEY NONCLUSTERED (UUID),
    CONSTRAINT UQ UNIQUE (ID)
)
GO

Create Table AnotherTable
(
    SomeTableID INT,

    FOREIGN KEY (SomeTableID) REFERENCES SomeTable(ID)
)
GO

修改

假设您的集中式数据库是Mart,并且只从源数据库中完成批量ETL,如果您将ETL直接发送到中央数据库(即不是通过Entity Framework),那么所有表都是在从分布式数据库重新填充后有UUID FK,您需要在ETL期间映射INT UKCs或在导入后修复它们(这需要INT FK上的临时NOCHECK约束步骤)。

加载ETL并映射INT键后,我建议您忽略/删除ORM模型中的UUID - 您需要在INT键上重新生成EF导航。

如果直接更新中央数据库或持续使用ETL并且使用EF作为ETL本身,则需要使用不同的解决方案。在这种情况下,将PK GUID保留为RI的FK,完全丢弃INT FK,并选择其他合适的列进行聚类(最小化页面读取)可能会减少总I / O.

答案 1 :(得分:1)

GUID具有重要意义,是的。您的索引是非聚簇的,但索引本身将快速分段,外键上的索引也是如此。大小也是一个问题:16字节而不是4字节整数。

您可以使用NEWSEQUENTIALID()函数作为列的默认值,以减少随机性并减少碎片。

但是,是的,我会说使用整数作为主键和参考将是最好的解决方案。

答案 2 :(得分:1)

一般来说,最好将INT用于主键/外键字段,无论这些字段是否为聚簇索引中的前导字段。该问题与JOIN性能有关,即使您使用UNIQUEINDENTIFIER作为NonClustered,或者即使您使用NEWSEQUENTIALID()来减少碎片,随着表变大,它将更加可扩展到INT字段之间的JOIN。 (请注意,我说PK / FK字段应始终为INT,因为有时候使用完全有效的自然键。)

在您的情况下,考虑到对实体框架的关注并在应用程序中而不是在数据库中生成GUID,请考虑使用INT作为PK / FK字段的替代建议,而不是在所有表中使用UNIQUEIDENTIFIER,只将它放在主用户/客户信息表中。我认为您应该能够基于GUID一次性查找客户INT标识符,缓存该值,然后对所有剩余操作使用INT值。是的,请确保GUID字段上有一个UNIQUE,NONCLUSTERED索引。

所有人都说,如果你的表永远不会(我的意思是从不与前两年相反),每个人的成长超过100,000行,那么使用UNIQUEIDENTIFIER就不那么容易了执行正常(给予适度不错的硬件,不会因其他进程负担过重或内存不足)。显然,由于使用UNIQUEIDENTIFIER而导致JOIN性能下降的程度将在很大程度上取决于系统的具体情况:硬件以及查询的类型,查询的编写方式以及系统的负载量。