哪一个是SQL Server中主键的最佳选择?
有一些示例代码:
e.g。
CREATE TABLE new_employees
(employeeId UNIQUEIDENTIFIER DEFAULT NEWID(),
fname VARCHAR(20) )
GO
INSERT INTO new_employees(fname) VALUES ('Karin')
GO
e.g。
CREATE TABLE new_employees
(
employeeId int IDENTITY(1,1),
fname varchar (20)
);
INSERT new_employees
(fname)
VALUES
('Karin');
[材料代码](或商业代码,材料的标识。例如客户标识符)
e.g。
CREATE TABLE new_employees(
[ClientId] [varchar](20) NOT NULL,
[fName] [varchar](20) NULL
)
INSERT new_employees
(ClientID, fname)
VALUES
('C0101000001',--customer identifier,e.g.'C0101000001' a user-defined code.
'Karin');
请给我一些建议,从三种类型的标识列或其他选项中选择主键。
谢谢!
答案 0 :(得分:21)
GUID
似乎是您主键的自然选择 - 如果您真的必须,您可能会争辩将其用于表的PRIMARY KEY。我强烈建议不要使用GUID
列作为群集密钥,默认情况下SQL Server会执行此操作,除非您明确指出到。
你真的需要分开两个问题:
主键是一个逻辑结构 - 唯一且可靠地标识表中每一行的候选键之一。这可以是任何事情,真的 - INT
,GUID
,字符串 - 选择对您的方案最有意义的内容。
群集密钥(在表上定义“聚簇索引”的一列或多列) - 这是与物理存储相关的东西,并且在这里,一个小而稳定,不断增加的数据类型是您的最佳选择 - INT
或BIGINT
作为您的默认选项。
默认情况下,SQL Server表上的主键也用作群集键 - 但这不一定是这样!我个人看到在将先前基于GUID的主/群集密钥分解为两个单独的密钥(GUID
上的主(逻辑)密钥和单独的{上的集群(排序)密钥)时可以获得巨大的性能提升{1}}列。
作为Kimberly Tripp - 索引女王 - 以及其他人已多次声明 - 由于群集密钥不是最佳的INT IDENTITY(1,1)
随机性,它将导致大量的页面和索引碎片,并导致一般性能不佳。
是的,我知道 - 在SQL Server 2005及更高版本中有GUID
- 但即使这样也不是真正完全顺序的,因此也遇到与newsequentialid()
相同的问题 - 只是少了一点显着如此。
然后还有另一个需要考虑的问题:表格上的聚类键也会被添加到表格中每个非聚集索引的每个条目上 - 因此你真的想确保它尽可能小。通常,对于绝大多数表来说,具有2亿行的GUID
应该足够 - 并且与作为群集密钥的INT
相比,您可以在磁盘上保存数百兆字节的存储空间。服务器内存。
快速计算 - 使用GUID
与INT
作为主要和群集密钥:
TOTAL:25 MB vs. 106 MB - 这只是在一张桌子上!
更多值得思考的东西 - 金佰利特里普的优秀作品 - 阅读,再读一遍,消化它!这是SQL Server索引福音,真的。
除非你有非常好的理由,否则我会争论使用GUID
几乎每个“真实”数据表作为其主键的默认值 - 它是唯一的,它是稳定的(从不改变),它是狭窄的,它会不断增加 - 你希望在群集密钥中拥有所有良好属性,以便快速可靠地执行SQL Server表!
如果您有一些“自然”键值也具有所有这些属性,那么您也可以使用它而不是代理键。但两个可变长度的字符串max。在我看来,每个20个字符都不符合这些要求。
答案 1 :(得分:5)
<强> IDENTITY 强>
赞成
CONS
<强> GUID 强>
赞成
因为它们{或多或少}保证是唯一的,所以多个表/数据库/实例/服务器/网络/数据中心可以独立生成它们,然后合并而不会发生冲突;
;
CONS
答案 2 :(得分:2)
在设计表时,您需要考虑的一件事是,您是否需要复制,分片或以其他方式将数据从一个地方移动到另一个地方。也许数据是由其他应用程序生成的,需要与您的数据保持同步。一个例子是移动应用程序,它创建数据然后与服务器同步。如果这样的事情是真的或可能是真的那么UNIQUEIDENTIFIER
将是用作主键的好选择。
UNIQUEIDENTIFIER
数据类型在用作聚簇索引时性能很差。是的,您可以使用newsequentialid()
,但如果在其他设备上生成这些值,则无法帮助您。共识似乎是聚簇索引最好与顺序和窄数据类型一起使用,如INT
或BIGINT
。
如果您不关心存储空间问题,那么您可以尝试同时使用IDENTITY
群集密钥和UNIQUEIDENTIFIER
主键。创建群集密钥 IDENTITY
列,并将其用于聚簇索引(但不能用作主键)。插件仍将按顺序进行,并且满足了它作为窄数据类型的要求。现在,您可以使用UNIQUEIDENTIFIER
作为主键。这将允许您在需要时移动,复制和/或分片数据。
群集密钥除了保持插入顺序之外没有其他目的,并且是查找给定查询的数据时所有其他非群集索引指向的内容。 群集密钥完全丢弃,并且可以在移动,复制和/或分片数据时重新生成,因为唯一性由UNIQUEIDENTIFIER
主键处理。
这是一篇很棒的文章,演示了在为聚集索引使用IDENTITY和UNIQUEIDENTIFIER时内部会发生什么。
答案 3 :(得分:1)
GUID很大,但具有在任何地方都是唯一的优势:这个或那个表,或者那个,如果你有GUID,那么其他一切都是可知的。如果这对你有用,那么很好,但你会在头顶上支付,并继续支付,支付和支付....
材质代码仅适用于较小的不可变键,如颜色或分类代码等。 R将始终为红色,G为绿色,为一个字节等。
当可能没有材料代码,或者自然键由多个材料代码组成在一起,或者自然键已经由其他标识列和/或GUID或自然键组成时,标识列会自行生成是可变的。是的,您可以使用GUID,但整数列在所有方面都更有效。
SQL 2012中提供的另一个选项是序列,类似于数据库级标识列。这是GUID和标识列之间的一个很好的中途,在某种意义上说,序列可以在许多表中使用,因此从给定的值,不仅行是可知的,但表也是 - 但你仍然可以使用如果您认为对您的数据足够,则为INT或BIGINT(或SMALLINT!)。这对于某些目的来说有点漂亮,有点像OO世界中的对象id。
请注意,许多或轻量级ORM要求表具有单个列主键,最好是整数列,并且除了INT IDENTITY PK之外的其他任何内容都可能无法正常运行。