Uniqueidentifier与IDENTITY vs. Material Code - 哪个是主键的最佳选择?

huo*_*125 14 database sql-server database-design sql-server-2012

哪一个是SQL Server中主键的最佳选择?
有一些示例代码:

Uniqueidentifiers

例如

CREATE TABLE new_employees
   (employeeId   UNIQUEIDENTIFIER      DEFAULT NEWID(),
   fname      VARCHAR(20) )
GO
INSERT INTO new_employees(fname) VALUES ('Karin')
GO
Run Code Online (Sandbox Code Playgroud)

标识列

例如

 CREATE TABLE new_employees
 (
  employeeId int IDENTITY(1,1),
  fname varchar (20)
 );

 INSERT new_employees
    (fname)
 VALUES
    ('Karin');
Run Code Online (Sandbox Code Playgroud)

[材料代码](或商业代码,材料的标识.例如客户标识符)

例如

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');
Run Code Online (Sandbox Code Playgroud)

请给我一些建议,从三种类型的标识列或其他选项中选择主键.

谢谢!

mar*_*c_s 22

GUID对于你的主键来说似乎是一个自然的选择 - 如果你真的必须这样做,你可能会争辩将它用作表的PRIMARY KEY.我强烈建议不要使用该GUID列作为群集密钥,默认情况下SQL Server会执行此操作,除非您明确告诉它不要.

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

  1. 主键是一个逻辑结构-候选键唯一和可靠地识别你的表中每一行的一个.这可以是任何东西,真的 - INT一个GUID,一个字符串 - 选择对你的场景最有意义的东西.

  2. 聚集键(列或定义表上的"聚集索引"列) -这是一个物理存储相关的事情,在这里,一个小的,稳定的,不断增长的数据类型是您最好的挑选- INTBIGINT为您的默认选项.

默认情况下,SQL Server表上的主键也用作群集键 - 但这不一定是这样!我个人看到在将先前基于GUID的主/群集密钥分解为两个单独的密钥(GUID单个INT IDENTITY(1,1)列上的主(逻辑)密钥和单独列上的群集(排序)密钥)时可以获得巨大的性能提升.

作为金佰利特里普 -该索引的女王 -和其他人说一个伟大的多次-一个GUID作为聚集键不是最优的,因为由于它的随机性,这将导致大量页面和索引碎片和一般的糟糕表现.

是的,我知道 - newsequentialid()在SQL Server 2005及更高版本中 - 但即使这样也不是真正的,完全顺序的,因此也会遇到与之相同的问题GUID- 只是不那么突出.

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

快速计算 - 使用INTvs. GUID作为主要和群集密钥:

  • 基表有1'000'000行(3.8 MB对15.26 MB)
  • 6个非聚簇索引(22.89 MB对91.55 MB)

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

还有一些值得思考的东西 - 金伯利·特里普的优秀作品 - 阅读,再读一遍,消化它!这是SQL Server索引福音,真的.

除非你有充分的理由,否则我认为INT IDENTITY几乎每个"真实"数据表都使用一个作为主键的默认值 - 它是唯一的,它是稳定的(永不改变),它是狭窄的,它不断增加 - 所有的好处您希望在群集密钥中具有的属性,以便快速可靠地执行SQ​​L Server表!

如果您有一些"自然"键值也具有所有这些属性,那么您也可以使用它而不是代理键.但两个可变长度的字符串最大.在我看来,每个20个字符都不符合这些要求.


Muh*_*sir 5

IDENTITY

PROS

  1. 存储空间小;
  2. 最佳连接/索引性能(例如,对于时间范围查询,最近插入的大多数行将在有限数量的页面上);
  3. 对数据仓库非常有用;
  4. 操作系统的本机数据类型,易于使用所有语言;
  5. 易于调试;
  6. 自动生成(通过SCOPE_IDENTITY()检索而不是分配);
  7. 不可更新(虽然有些人认为这是一个缺点,奇怪的是).

缺点

  1. 无法通过应用程序可靠地"预测" - 只能在INSERT之后检索;
  2. 在多服务器环境中需要一个复杂的方案,因为在某些形式的复制中不允许使用IDENTITY;
  3. 如果没有明确设置为PRIMARY KEY,则可以重复.
  4. 如果表上的聚集索引的一部分,这可以创建一个插入热点;
  5. 专有且不直接携带;
  6. 只在一张桌子内独一无二;
  7. 可能会出现间隙(例如,回滚交易),这可能导致鸡小型警报.

GUID

PROS

  1. 因为它们{或多或少}保证是唯一的,所以多个表/数据库/实例/服务器/网络/数据中心可以独立生成它们,然后合并而不会发生冲突;

  2. 某些形式的复制所需;

  3. 可以在数据库外部生成(例如,通过应用程序);
  4. 分布式值可防止热点(只要您不对此列进行聚类,这可能会导致异常高的碎片).

缺点

  1. 更宽的数据类型导致索引性能下降(如果是群集,每个插入几乎保证'脏'不同页面),并且存储要求增加;
  2. 调试很麻烦(其中userid = {BAE7DF4-DDF-3RG-5TY3E3RF456AS10});
  3. 可更新的(需要传播变化,或完全阻止活动);
  4. 对某些环境中的时间回滚敏感(例如夏令时回滚);
  5. GROUP BY和其他设置操作通常需要CAST/CONVERT;
  6. 并非所有语言和环境都直接支持GUID;
  7. 没有像SCOPE_GUID()那样的语句来确定生成的值,例如通过NEWID();