我想看一个例子:
是否有时候选择数据库会对上述示例产生影响?
答案 0 :(得分:33)
这似乎是一个关于代理键的问题,它们总是一个自动递增的数字或GUID,因此是一个列,而不是自然键,这通常需要多条信息才能真正独一无二。如果你能够拥有一个只有一列的自然键,那么无论如何,这一点显然没有实际意义。
有些人会坚持只使用其中一种。花足够的时间使用生产数据库,您将了解到没有与上下文无关的最佳实践。
其中一些答案使用SQL Server术语,但这些概念通常适用于所有DBMS产品:
聚簇索引。当数据库只能附加到聚簇索引时,聚簇索引始终表现最佳 - 否则,数据库必须执行page splits。请注意,这仅适用于密钥为顺序的情况,即自动增量序列或顺序GUID。任意GUID可能会更糟糕的表现。
关系。如果您的密钥长度为3,4,5列,包括字符类型和其他非紧凑数据,则最终会浪费巨额金额如果你必须在其他20个表中创建与该键的外键关系,那么空间会随后降低性能。
唯一性。有时您不会拥有真正的自然键。也许你的表是某种日志,你可以同时获得两个相同的事件。或者,您的真实密钥类似于物化路径,只有在已插入行之后才能确定。无论哪种方式,您总是希望您的聚集索引和/或主键是唯一的,因此如果您没有其他真正独特的信息,您别无选择,只能使用代理键。
兼容性。大多数人永远不会处理这个问题,但如果自然键包含类似hierarchyid
的内容,则有些系统可能无法读取它。在这种情况下,您再次必须创建一个简单的自动生成的代理键供这些应用程序使用。即使您在自然键中没有任何“怪异”数据,一些DB库在处理多列主键时也会遇到很多麻烦,尽管这个问题很快就会消失。
存储。许多使用数据库的人从不使用足够大的数据库来处理这个因素。但是当一个表有数十亿或数万亿行时,你可能希望在这个表中尽可能保留绝对最小的数据量。
复制。是的,您可以使用GUID或顺序GUID。但GUID有自己的权衡,如果由于某种原因你不能或不想使用GUID,那么多列自然键是复制方案的更好选择,因为它本质上是全局的唯一的 - 也就是说,您不需要特殊的算法来使其独一无二,它是唯一的按照定义。这使得分布式体系结构的推理变得非常容易。
插入/更新效果。代理键不是免费的。如果您有一组经常查询的唯一和列,那么您需要在这些列上创建覆盖索引;索引最终几乎与表一样大,这会占用空间,而要求每次进行任何修改时都要更新第二个索引。如果您有可能在表上只有一个索引(聚集索引),那么您应该这样做!
这就是刚刚想到的东西。如果我突然想起其他的话,我会更新。
答案 1 :(得分:3)
你几乎总是想要一个主键,所以我假设选择在选择现有的两列作为主键,或者创建一个新的自动递增PK并在两列上放置一个普通的唯一约束。 / p>
如果需要2列主键:
如果需要自动增量主键:
答案 2 :(得分:3)
我认为几乎总是更好(从应用程序开发人员的角度来看,至少)使主键成为自动生成的键,并在多列上创建UNIQUE约束和索引。
我遇到了几个令人头疼的情况,因为DBA认为多列主键总是足够的,未来的需求变化证明这是不正确的。
答案 3 :(得分:1)
一些例子......
适当的:
不适当:
对于OLAP系统中的维度表 - 您希望使维度键尽可能小,以使事实表尽可能小(且快速)。
当您不确定组合是否唯一时。虽然这是一个非常糟糕的例子,但对于多列PK来说,“人员”表将是一个糟糕的选择。
答案 4 :(得分:0)
适当的时候的一个例子是你有一个链接表,其中包含连接不同表的外键字段。
通常,在可能的情况下使用现有的标识字段作为主键可能是个好主意。如果你没有自然的id字段,并且你必须结合很多字段来获得一个独特的PK,那么最好使用一个自动编号。超过2个字段的主键可能会变得混乱。
答案 5 :(得分:0)
当我们使用多列索引和键时,我们发现应用程序的性能有了很大提高。它允许我们在最常见的查询上创建索引,并且甚至没有访问主表,因为整个select子句可以在索引中。但是,这取决于您的应用和数据集。
答案 6 :(得分:0)
有时复合自然键具有直观感。例如。假设您有一个公司的表(PK是ComapnyId),其中列有公司的一些详细信息。您还需要在其历史记录中存储公司的CEO名称。自然不变的是,一家公司一次只能拥有一名CEO。然后直观地创建一个CompanyCeo表,其中包含CompanyId的复合PK(公司表中的FK到CompanyId)+ FromDate。该表中的其他列可能是ToDate和CeoName。通过这种方式,您可以保证只有一位CEO可以在特定日期开始。