我应该设计一个主键为varchar或int的表吗?

时间:2009-08-19 16:40:37

标签: sql sql-server database-design

我知道这是主观的,但我想知道人们的意见,并希望在设计sql server表结构时可以应用一些最佳实践。

我个人觉得在固定(最大)长度varchar上键入一个表是禁忌,因为它意味着必须在使用它作为外键的任何其他表中传播相同的固定长度。使用int,将避免必须在整个板上应用相同的长度,这必然导致人为错误,即1个表具有varchar (10),而另一个varchar (20)

这听起来像是最初设置的噩梦,而且意味着将来维护表格也很麻烦。例如,假设keyed varchar列突然变成12个字符而不是10个字符。你现在必须去更新所有其他表格,这可能是一个巨大的任务年代。

我错了吗?我错过了什么吗?我想知道其他人对此的看法,以及坚持使用int作为主键是避免维护噩梦的最佳方法。

13 个答案:

答案 0 :(得分:39)

答案 1 :(得分:17)

我肯定会建议在每个表中使用INT NOT NULL IDENTITY(1,1)字段作为 主键。

使用IDENTITY字段,您可以让数据库处理确保它真正唯一的所有细节,并且INT数据类型只有4个字节并且已修复,因此它更容易且更适合用于主数据库表格中的(和群集)键。

你是对的 - INT是一个INT是一个INT - 它不会改变它的大小,所以你不必再重新创建和/或更新你的外键关系。

使用VARCHAR(10)或(20)只占用太多空间 - 10或20个字节而不是4个,而且许多人都不知道 - 聚类键值将在每个索引上重复在表上的每个非聚集索引上输入,因此可能会浪费大量空间(不仅仅是在磁盘上 - 这很便宜 - 而且还在SQL Server的主内存中)。此外,由于它的变量(可能是4,可能是20个字符),因此SQL服务器更难以正确维护良好的索引结构。

马克

答案 2 :(得分:4)

我同意一般来说INT(或身份)字段类型是大多数“普通”数据库设计的最佳选择:

  • 它不需要“算法”来生成id / key / value
  • 你有快速(呃)连接,优化器可以在范围内更加努力工作
  • 你正在遵循事实上的标准

也就是说,您还需要了解您的数据。如果你打算通过一个带符号的32位int,你需要考虑unsigned。如果你想要通过它,也许你想要的64位整数。或者您可能需要UUID / hash来更轻松地在数据库实例/分片之间进行同步。

不幸的是,它取决于和YMMV,但我肯定使用int / identity,除非你有充分的理由

答案 3 :(得分:3)

就像你说的那样,一致性是关键。我个人使用未签名的整数。除非你正在使用大量数据,否则你不会用完它们,并且你总是可以知道任何关键列需要是那种类型,你永远不必为各个列寻找合适的值。

答案 4 :(得分:2)

基于无数次执行此练习然后用结果支持系统,有一些警告说明INT总是更好。一般来说,除非有理由,否则我会同意。然而,在战壕中,这里有一些优点和缺点。

<强> INT

  • 使用除非有充分理由不这样做。

<强> GUID

  • 唯一性 - 一个例子是程序的远程部分之间存在单向通信的情况,而需要启动的部分不是数据库的一部分。在这种情况下,在远程端设置Guid是安全的,而选择INT不是。
  • 唯一性再次 - 一个更加遥远的场景是一个系统,其中多个客户共存于不同的数据库中,并且使用一套程序在类似用户之类的客户之间进行迁移。如果该用户注册另一个程序,则可以在那里使用他们的用户记录而不会发生冲突。另一种情况是客户是否相互获取实体。如果两者都在同一系统上,他们通常会希望迁移更容易。基本上,客户之间的任何频繁迁移。
  • 难以使用 - 即使是经验丰富的程序员也无法记住guid。在进行故障排除时,必须复制和粘贴查询标识符通常很令人沮丧,尤其是在使用远程访问工具完成支持时。经常引用SELECT * FROM Xxx WHERE ID = 7比SELECT * FROM Xxx WHERE ID ='DF63F4BD-7DC1-4DEB-959B-4D19012A6306'

  • 更容易
  • 索引 - 对guid字段使用聚簇索引需要对数据页进行不断的重新排列,并且索引效率不如INT甚至短字符串。它可以扼杀性能 - 不要这样做。

<强> CHAR

  • 可读性 - 虽然传统观点认为没有人应该在数据库中,但系统的实际情况是人们可以访问 - 希望是您组织的人员。当这些人不熟悉连接语法时,没有很多其他查询,带有int或guid的规范化表格就不清楚了。具有SOME字符串键的相同规范化表可用于故障排除。我倾向于将此用于我在安装时提供记录的表类型,因此它们不会发生变化。当密钥为“已关闭”或“待定”而非数字时,主要表格上的StatusID等内容更有用。在这些领域使用传统密钥可以将容易解决的问题转变为需要开发人员帮助的问题。即使是让可疑人员访问数据库导致这样的瓶颈也很糟糕。
  • 约束 - 即使您使用字符串,也要保持固定长度,从而加快索引速度,并添加约束或外键以防止垃圾进入。有时使用此字符串可以允许您删除查找表并将选择维护为代码中的简单枚举 - 限制进入此字段的数据仍然很重要。

答案 5 :(得分:1)

对于best performance,99.999%的时间主键应该是一个整数字段。

除非您要求主键在数据库中的多个表或多个数据库中是唯一的。我假设您询问MS SQL-Server,因为这是您的问题被标记的方式。在这种情况下,请考虑使用GUID字段。虽然优于varchar,但GUID字段性能不如整数。

答案 6 :(得分:1)

使用INT。你的积分都是有效的;我会优先考虑:

  1. 易于使用SQL自动增量功能 - 为什么要重新发明轮子?
  2. 可管理性 - 您不希望更改关键字段。
  3. 性能
  4. 磁盘空间
  5. 1&amp; 2需要开发人员的时间/精力/精力。 3&amp; 4你可以扔硬件。

答案 7 :(得分:1)

如果Joe Celko在这里,他会有一些刺耳的话......; - )

我想指出,INT作为一项严格而快速的规则并不总是合适的。假设您有一个车辆桌子,上面有各种类型的汽车卡车等。现在说你有一个VehicleType表。如果您想获得所有卡车(可以使用INT身份种子):

SELECT V.Make, V.Model
FROM Vehicle as V
INNER JOIN VehicleType as VT
ON V.VehicleTypeID = VT.VehicleTypeID
WHERE VT.VehicleTypeName = 'Truck'

现在,在VehicleType上使用Varchar PK:

SELECT Make, Model
FROM Vehicle 
WHERE VehicleTypeName = 'Truck'

代码更清洁,你避免加入。也许连接不是世界末日,但如果你的工具箱中只有一个工具,那么你就会错过一些提高性能和更清晰模式的机会。

只是一个想法。 : - )

答案 8 :(得分:0)

虽然通常建议使用INT,但这实际上取决于您的情况。

如果您关注可维护性,那么其他类型也是可行的。例如,您可以非常有效地使用Guid作为主键。有理由不这样做,但一致性不是其中之一。

但是,是的,除非你有充分的理由不这样做,否则int最容易使用,并且最不可能导致任何问题。

答案 9 :(得分:0)

使用PostgreSQL,我通常使用“Serial”或“BigSerial”数据类型来生成主键。这些值是自动递增的,我总能找到易于使用的整数。它们基本上等同于设置为“auto_increment”的MySQL整数字段。

答案 10 :(得分:0)

人们应该认真考虑32位范围是否足以满足您的需求。 Twitter的状态ID是32位INT,当他们用完时他们遇到了麻烦。

在这种情况下是否使用BIGINT或UUID / GUID是有争议的,我不是硬核数据库人,但是UUID可以存储在固定长度的VARCHAR中,而不必担心你需要更改字段大小

答案 11 :(得分:0)

我们必须记住,表的主键不应该具有“业务逻辑”,它应该只是它所属记录的标识。遵循这个简单的规则,int和特别是identity int是一个非常好的解决方案。通过询问varchar我猜你的意思是使用例如“全名”作为“人”表的关键。但是,如果我们想将名称从“George Something”改为“George A. Something”呢?该领域的规模是多少?如果我们改变大小,我们也必须改变所有外表上的大小。所以我们应该避免键上的逻辑。有时我们可以使用社交ID(整数值)作为键,但我也避免使用它。现在,如果一个项目有扩展的前景,你应该考虑使用Guids(uniqueidentifier SQL类型)。

答案 12 :(得分:0)

请记住,这是一个非常古老的问题,我仍然希望将未来读者使用varchar与代理键进行讨论:

  1. 具有多个复制机器的环境
  2. 需要在插入行之前知道要插入的行的ID的场景(即,客户端分配此ID,而不是数据库)