【发布时间】:2008-10-23 16:11:55
【问题描述】:
在新建数据库表时,选择主键的数据类型应该考虑哪些因素?
【问题讨论】:
标签: sql database-design
在新建数据库表时,选择主键的数据类型应该考虑哪些因素?
【问题讨论】:
标签: sql database-design
很抱歉,我发现我对相关问题的回答(您可以查看this 和this)可能适用于这个问题。我对它们进行了一点改造......
您会发现很多帖子都在讨论这个问题,并且您做出的每个选择都有其优点和缺点。这些论点通常是指关系数据库理论和数据库性能。
在这个问题上,我的观点很简单:代理主键总是有效,而 自然键在这些日子里可能并不总是有效,这有多种原因:字段太短,规则更改等。
到目前为止,您已经在这里猜到了,我基本上是唯一标识符/代理主键团队的成员,即使我欣赏并理解此处提出的论点,我仍在寻找这样的案例: “自然”键比代理好...
除此之外,支持这一基本规则的最重要但总是被遗忘的论点之一与代码规范化和生产力有关:
每次我创建一个表,我会不会浪费时间
我对所有这些问题的回答都是否定的:
所以在过去的五年里,我一直在遵循一个非常基本的规则:每个表(我们称之为“myTable”)都有其第一个字段,称为 'id_MyTable',它属于 uniqueIdentifier 类型。即使此表支持“多对多”关系,其中字段组合提供了一个非常可接受的主键,我更喜欢创建这个 'id_myManyToManyTable' 字段作为唯一标识符,只是为了遵守规则,因为,最后,不疼。
主要优点是您不必再关心代码中主键和/或外键的使用。获得表名称后,您就知道 PK 名称和类型。一旦您知道在您的数据模型中实现了哪些链接,您就会知道表中可用外键的名称。
如果您仍然想在表格中的某个位置放置“自然键”,我建议您按照标准模型构建它,例如
Tbl_whatever
id_whatever, unique identifier, primary key
code_whatever, whateverTypeYouWant(whateverLengthYouEstimateTheRightOne), indexed
.....
其中 id_ 是主键的前缀,code_ 用于“自然”索引字段。有些人会争辩说应该将 code_ 字段设置为唯一的。确实如此,并且可以通过 DDL 或外部代码轻松管理它。请注意,许多“自然”键是计算出来的(发票号码),因此它们已经通过代码生成
我不确定我的规则是不是最好的。但它是一个非常有效的!如果每个人都在应用它,我们将避免浪费时间回答这类问题!
【讨论】:
如果使用数字键,请确保数据类型足够大以容纳您可能希望表增长到的行数。
如果使用 guid,是否需要考虑存储 guid 所需的额外空间?针对 guid PK 进行编码对于应用程序的开发人员或用户来说是否会很痛苦。
如果使用复合键,您确定组合列始终是唯一的吗?
【讨论】:
我不太喜欢他们在学校教的东西,即使用“自然键”(例如图书数据库中的 ISBN),甚至使用由 2 个或更多字段组成的主键。我永远不会那样做。所以这是我的小建议:
编辑:
好的,我想我需要稍微解释一下我的选择。
为您的主键在所有表中使用相同的专用列名称,只会使您的 SQL 语句更易于构建,并且对其他人(可能不熟悉您的数据库布局)更容易去理解。尤其是当你做很多 JOINS 之类的事情时。您无需查找特定表的主键,您已经知道,因为它在任何地方都是相同的。
GUID 与 INT 在大多数情况下并不那么重要。除非您达到 GUID 的性能上限或进行数据库合并,否则您不会遇到任何重大问题。 但是我更喜欢 GUID 是有原因的。 GUID 的全局唯一性总有一天会派上用场。也许您现在看不到它的需要,但是诸如将部分数据库同步到笔记本电脑/手机,甚至在不需要知道它们在哪个表中的情况下查找数据记录之类的事情,都是 GUID 优势的很好例子提供。 Integer 仅标识一个表上下文中的记录,而 GUID 标识任何位置的记录。
【讨论】:
在大多数情况下,我使用 identity int 主键,除非场景需要大量复制,在这种情况下我可能会选择 GUID。
我(几乎)从未使用过有意义的键。
【讨论】:
除非您有一个非常方便的可用自然键,否则请始终使用数字类型的合成(也称为代理)键。即使您确实有可用的自然键,您也可能需要考虑使用合成键并在您的自然键上放置一个额外的唯一索引。考虑一下在联邦法律发生变化时使用社会安全号码作为 PK 的高级数据库发生了什么,转换为合成密钥的成本是巨大的。
另外,我不同意将每个主键命名为相同的做法,例如“ID”。这使得查询更难理解,而不是更容易。主键应以表命名。例如employee.employee_id、affiliate.affiliate_id、user.user_id 等。
【讨论】:
不要使用浮点数值类型,因为浮点数无法正确比较是否相等。
【讨论】:
到目前为止,我使用了唯一标识符 (GUID) 或递增整数。
干杯 马蒂亚斯
【讨论】:
在现实世界中有意义的数字通常是个坏主意,因为现实世界时常会改变有关如何使用这些数字的规则,特别是允许重复,然后你就会弄得一团糟你的手。
【讨论】:
我偏爱使用生成的整数键。如果您希望数据库变得非常大,您可以使用 bigint。
有些人喜欢使用指南。优点是您可以在不更改任何键的情况下合并数据库的多个实例,但缺点是性能可能会受到影响。
【讨论】:
对于“自然”键,任何适合列的数据类型。人工(代理)键通常是整数。
【讨论】:
这一切都取决于。
a) 您可以将唯一的连续数字作为主键吗?如果是,那么选择 UniqueIdentifier 作为主键就足够了。 b) 如果您的业务需求是需要字母数字主键,那么您必须选择 varchar 或 nvarchar。
这是我能想到的两个选项。
【讨论】:
一个重要因素是您要存储多少数据。我在一家网络分析公司工作,我们有大量数据。因此,由于大小,我们的 pageviews 表上的 GUID 主键会杀死我们。
经验法则:为了获得高性能,您应该能够将整个索引存储在内存中。向导很容易打破这个!
【讨论】:
在可以信任的情况下使用自然密钥。自然密钥的某些来源是不可信的。多年前,社会保障局过去常常将同一个 SSN 分配给两个不同的人。他们现在可能已经解决了这个问题。
您可能可以相信车辆的 VIN 和书籍的 ISBN(但不能相信可能没有 ISBN 的小册子)。
如果您使用自然键,自然键将确定数据类型。
如果您不能信任任何自然密钥,请创建合成密钥。为此,我更喜欢整数。为合理扩展留出足够的空间。
【讨论】:
我通常使用所有表的 GUID 列主键(mssql 中的 rowguid)。什么可能是自然键我制作了独特的约束。一个典型的例子是用户必须填写并确保其唯一性的产品标识号。如果我需要一个序列,比如在发票中,我会构建一个表来保存最后一个数字和一个存储过程以确保序列化访问。或者 Oracle 中的序列 :-) 我讨厌自然键的“社会安全号码”样本,因为该号码在注册过程中永远不会出现。导致需要一个生成虚拟数字的方案。
【讨论】:
我通常总是使用整数,但这里有一个有趣的观点。
https://blog.codinghorror.com/primary-keys-ids-versus-guids/
【讨论】:
尽可能尝试使用作为自然键的主键。例如,如果我有一个每天记录一条记录的表,那么 logdate 将是一个很好的主键。否则,如果没有自然键,只需使用 int。如果您认为您将使用超过 20 亿行,请使用 bigint。有些人喜欢使用 GUID,这很好用,因为它们是独一无二的,而且你永远不会用完空间。但是,如果您只是进行临时查询,它们不必要地冗长,并且难以输入。
【讨论】: