在一个相当的动画讨论在我的团队我是为了为什么大多数人喜欢作为主键。我们有以下组

  1. Int/BigInt其自动增量足够好主键。
  2. 应至少有3所列的主要关键。
  3. Id,GUID和人可读的行标识符的所有区别对待。

什么是最好的办法,PKs?这将是真棒,如果你能证明你的意见。是否有更好的办法是,上述?

编辑:任何人都有一个简单的样品/算法来产生人类可读的标识符进行的鳞片?

有帮助吗?

解决方案

如果您要在偶尔连接的应用程序的数据库之间进行任何同步,那么您应该使用GUID作为主键。这是一种调试的痛苦,所以除了这种情况,我倾向于坚持自动增量的整数。

自动增量整数应该是您的默认值,使用它们应该是合理的。

其他提示

我没有看到一个答案指出(我认为)真正的基本点 - 即主键是保证你不会在同一个真实世界的表中获得两个条目实体(在数据库中建模)。这种观察有助于确定主键的优点和选择。

例如,在(US)州名称和代码表中,名称或代码可以是主键 - 它们构成两个不同的候选键,其中一个(通常是较短的 - 代码)是被选为主键。在函数依赖的理论(和连接依赖--1NF到5NF - 它是关键而不是主键的候选键。

对于反例,人名通常是主键的错误选择。很多人都使用“John Smith”这个名字。或其他一些类似的名字;甚至考虑到中间名(记住:不是每个人都有一个 - 例如,我没有),有很多重复的余地。因此,人们不会使用名称作为主键。他们发明了人工密钥,例如社会安全号码(SSN)或员工编号,并用它们来指定个人。

理想的主键是短小,独特,令人难忘和自然。在这些特征中,唯一性是强制性的;考虑到现实世界数据的限制,其他人必须屈服。

因此,在确定给定表的主键时,您必须查看该表所代表的内容。表中的哪些列集或列集唯一标识表中的每一行?这些是候选键。现在,如果每个候选键由4列或5列组成,那么您可能会认为这些列太笨拙而无法制作好的主键(主要是基于短路)。在这种情况下,您可能会引入代理键 - 人工生成的数字。通常(但不总是)一个简单的32位整数就足以代替密钥。然后,将此代理键指定为主键。

但是,您必须仍然确保其他候选密钥(代理密钥也是候选密钥,以及所选主密钥)都保持为唯一标识符 - 通常通过放置对这些列集的唯一约束。

有时,人们发现难以确定哪一行是唯一的,但应该有一些事情要做,因为简单地重复一条信息并不会使它更加真实。如果你不小心并且确实得到两个(或更多)声称存储相同信息的行,然后你需要更新信息,则存在危险(特别是如果你使用游标),你将只更新一行而不是每一行,所以行不同步,没有人知道哪一行包含正确的信息。

在某些方面,这是一个非常强硬的观点。

我在使用GUID时没有特别的问题,但是它们往往是 big (如16-64字节),并且它们经常被使用。通常,一个非常好的4字节值就足够了。使用GUID,其中4字节值足以浪费磁盘空间,并且甚至减慢了对数据的索引访问速度,因为每个索引页的值更少,因此索引将更深,并且必须读取更多页面才能访问信息。

这仅仅是一个宗教问题,因为人们谋求一个普遍正确的答案。事实上,两者你的团队,这样线显示了这么多的分歧应该是一个线索,有很好的理由使用所有解决方案的描述,在不同的情况。

  • 代理键是有用的,在没有其他属性或设定的属性表格中的适当的识别排。
  • 自然键是优选的,可能时,以使表格更多的人阅读。自然键,也允许外国的关键在一个从属表含有一个真正的价值,而不是一个替代标识。E.g。当你需要的商店 state (加州,德克萨斯州,纽约)以及可能使用 char(2) 自然的关键,而不是一个int.
  • 使用的化合物主键在适当情况下。不要添加"id"代理键不必要地当一个非常好的化合物关键的存在(特别是在许多对多表)。一个任务期限为三列的关键在每个表是绝对荒谬的。
  • Guid是一个解决方案时需要保持的独特性在多个站点。他们也是方便的,如果你需要价值观中的主要关键是独特的,但没有下令或连续的。
  • INT与BIGINT:这是不常见的,一个表 需要 64位范围内对于主键,但是与性增加了64位的硬件,它不应该是一个负担,并提供了更多的保证,你不会溢出。INT当然是较小,因此,如果空间可以得到一个微弱的优势。

我喜欢数据库程序员博客作为此类信息的来源。

主键有3列?我会说列应该有业务规则要求的适当的唯一约束,但我仍然有一个单独的代理键。复合键意味着业务逻辑进入密钥。如果逻辑发生变化,那么整个架构都会被搞砸。

我喜欢我的独特。

我总是使用代理键。代理键(通常是标识列,自动增量或GUID)是密钥不存在于数据本身中的密钥。另一方面,自然键是一个唯一标识行的键。就像我在生活中所说的那样,几乎没有任何真正的自然键。甚至像美国的SSN这样的东西也不是天生的关键。复合主键是一种等待发生的灾难。您无法编辑任何数据(这是任何自然键的复合或无复合的主要缺点),但更糟糕的是使用复合键,现在您必须将该关键数据保存到每个相关表中。真是个巨大的浪费。

现在,为了选择代理键,我坚持使用标识列(我主要在MS SQL Server中工作)。 GUID太大,Microsoft建议反对将它们用作PK。如果你有多个服务器,你需要做的只是增加10或20或你认为你需要同步/扩展到的最大服务器数量,并且只需要为每个后续服务器上的每个表添加种子,你永远不会有数据冲突。

当然,由于增量,我将标识列设为BigInt(也称为long [64位])。

进行一些数学运算,即使你使增量为100,你的表中仍然可以有92,233,720,368,547,758(> 92千万亿)行。

我认为在短语“Primary”中使用“Primary”一词。关键是真正意义上的,误导性的。

首先,使用“键”的定义。是表中必须唯一的属性或属性集,

然后,任何密钥都有几个通常相互矛盾的目的。

  1. 将连接条件用作子表中与该父表有关系的一个或多个记录。 (在这些子表中明确或隐式定义外键)
  2. (相关)确保子记录必须在父选项卡中具有父记录; e(子表FK必须作为父表中的键存在)
  3. 增加需要快速查找表中特定记录/行的查询的性能。

  4. 通过防止表示相同逻辑实体的重复行插入表来确保数据一致性。 (这通常称为“自然”键,应该包含相对不变的表(实体)属性。)

  5. 显然,任何非有意义的非自然键(如GUID或自动生成的整数)完全无法满足#4。

    但是,通常,对于许多(大多数)表,一个可以提供#4的完全自然的键通常由多个属性组成,并且过宽,或者太宽以至于将其用于#1,#2或#3目的将导致不可接受的性能后果。

    答案很简单。使用两者。对其他子表中的所有Joins和FK使用简单的自动生成整数键,但要确保每个需要数据一致性的表(很少有表没有)具有备用的自然唯一键,以防止插入不一致的数据行。 ..另外,如果你总是同时使用两者,那么所有反对使用自然键的反对意见(如果它改变了怎么办?我必须改变它被引用为FK的每个地方)都没有实际意义,因为你没有使用它。 ..你只是在一个PK中使用它,以避免不一致的重复数据......

    对于GUID,要非常小心地使用它们,因为在索引中使用guid可以软管索引碎片。用于创建它们的最常用算法是“随机”。最高位位置的guid部分...这增加了添加新行时常规索引碎片整理/重新索引的要求。

稍微偏离主题,但我觉得有必要加入......

如果您的主键是GUID, 使其成为聚集索引。由于GUID是非顺序的,因此几乎每次插入时数据都将重新排列在磁盘上。 (哎呀。)如果使用GUID作为主键,它们应该是非聚簇索引。

你不应该做的一件事是使用智能钥匙。这是关键,有关记录的信息在密钥本身中编码,最终会咬你。

我在一个地方工作,其中主键是帐户ID,它是字母和数字的组合。我不记得任何细节,但是,例如,那些特定类型的帐户将在600范围内,而另一种类型,从400开始。这很好,直到该客户决定要求两者工作类型。或者改变了他们所做的工作类型。

另一个地方,使用树中的位置作为记录的主键。所以会有如下记录。

Cat1.subcatA.record1
Cat1.subcatA.record2
Cat1.subcatB.record1
Cat2.subcatA.record1

当然,客户想要的第一件事就是在树中移动物品。整套软件在此之前就已经死了。

拜托,拜托,如果您正在编写我需要维护的代码,请不要使用智能密钥!

我喜欢将自动增量作为主键。我内心深处知道这是一个警察,但它确实使数据在添加时很容易排序(ORDER BY ID DESC,f'r实例)。

3列听起来非常严厉,人性化解析。

这就是权衡 - 你需要多少关系能力,而不是让人们在这里理解这个表格(对于存储过程或程序化界面)。

自动增量适用于我们人类。 : - (

一般来说,这取决于。

就个人而言,我喜欢自动增量投注。

但是,我可以告诉你的一件事是永远不要相信来自其他来源的数据作为你的钥匙。我发誓,每次我做完,它都会回来咬我。好吧,再也不会!

  

至少应该有3列构成主键。

我不明白这一点。

您是在谈论“自然键”,例如“姓名和出生日期”?一个自然键可能是理想的,如果它存在,但大多数自然键的候选者要么不是唯一的(几个具有相同名称的人),要么不恒定(有人可以更改其名称)。

  

Int / BigInt哪个自动增量是足够好的主键。

我更喜欢Guid。自动增量的潜在问题是值(例如“订单ID”)由数据库实例(例如,通过“销售数据库”)分配......这将不完全有效(相反,您开始需要复合键) )如果您需要合并由多个数据库实例创建的数据(例如,从多个销售办事处各自使用自己的数据库)。

RE GUID的

注意这是否真的非常非常真正大数据库,大量负载和快速访问。

在我上一份工作中,我们拥有1亿到5亿条记录的数据库,我们的数据库人员强烈反对GUID,以及适当大小的十进制数。他们认为(在Oracle下)字符串内部存储的大小差异Guid - vs- a十进制值会在查找中产生非常显着的差异。 (更大的键=更深的树遍历)

GUID的随机性也会显着降低索引页面的填充因子 - 这会大大增加撕裂和磁盘I / O.

自动增加列。我能够使我的代码与SQL Server或Oracle无缝协作,一个使用身份,另一个使用序列通过我的DAL,我不能更快乐。我同意,如果您正在复制或发送数据以便稍后在处理时接收它,则GUID有时是必要的。

我总是用一种替代的关键-一个自增整数被称为'id'。我可以看到很多理由来这样做,即使另一个选择是明显的:

  • 一致性
  • 数据独立(独特的,不是被摧毁的变化格式)
  • 人阅读的

...并没有合理的理由不:

  • 模糊性,在加入? 锯齿表的是一个更好的做法,恕我直言
  • 最佳的表吗?-删除一个字节每个项目都是不成熟的优化,恕我直言
  • 每表决定?-不再是一致的
  • 扩展的问题?-是吗?为什么?
  • 分级数据结构?-这是denormalising一个整体的其他问题的宗教。我只想说我是个风扇在一些情况下在理论上,但是从来没有在实践:)

合理的理由反对,我没有想到或遇到过但是总是表示欢迎...

这是一个经典的“它取决于”。每个项目都没有正确答案。我喜欢不同的情况。这取决于我是否使用ORM以及它支持的内容。它取决于整体架构(分布式或非分布式)等。只需选择一个你认为可行的方法,然后继续争论标签和空格。

我倾向于使用选项#1或#3,具体取决于大小,连接人数以及是否是多数据库服务器情况。

选项#2对我没有多大意义。如果三者中的任何一个不足以识别唯一记录,则可能(不经过额外的阴谋)两个记录在所有三列中显示具有相同值的两个记录。如果要对三者的任意组合强制执行唯一性,则只需为它们添加索引。

我只使用自动增量int或GUID。 99%的时间我使用自动增量int。这正是我第一次学习数据库时所教会使用的,并且从未遇到过不使用它们的原因(虽然我知道为什么GUID会更好)。

我喜欢自动增量整数,因为它有助于提高可读性。例如,我可以说“看一下记录129383”。而且很容易让某人进去找到它。使用GUID几乎不可能做到。

过去的一个基本的定义性的答案,什么构成的 很好的 主要关键是左主要宗教和休息室的论点。如果你有什么,这是,而且将永远、地图的唯一的一个人行,那么它将作为一个主要关键。过去这一点,还有其他的考虑因素:

  • 是主要的关键定义不能过于复杂吗?它避免引入不必要的复杂性,为了下一个"最佳做法"?
  • 是否有更好的可能的主要关键,这将需要较小的开销,为该数据库以处理(即整数与VARCHAR,等等)?
  • 我绝对肯定的独特性和限定性,不变的是我的主要关键不会改变?

这最后一个是有可能的是什么吸引了大多数人使用的东西喜欢Guid或自递增整数列,因为依靠的东西喜欢的地址,电话号码,一个最后的名称、等等,只是不切。唯一不变的人,我可以认为是社会安全网,但后来我不是100%确定有关剩余的那些永远独特的。

我们希望这有助于增加一些澄清...

我接近主键的方式(我觉得最好)是避免使用“默认”键。做法。这意味着不是仅仅单击一个自动递增的整数并将其调用一天,我会查看问题,并说“是否有一列或一组列始终是unqiue且不会更改?”如果答案是肯定的,那么我采用这种方法。

几乎总是整数。

除了更小/更快的处理之外,它们还有其他充分的理由。你宁愿写下哪一个 - “404040”或“3463b5a2-a02b-4fd4-aa0f-1d3c0450026c”?

只是略微相关,但是我最近开始做的一件事是当我有小分类表(基本上代表代码中的ENUM)时,我会将主键设为char(3)或char(4) )。然后我创建代表查找值的主键。

例如,我有一个内部销售代理的报价系统。我们有“成本类别”每个引用行项目都分配了一个...所以我有一个名为'tCostCategories'的类型查找表,其中主键是'MTL','SVC','TRV','TAX','ODC'。查找表中的其他列存储更多细节,例如代码的正常英语含义,“材料”,“服务”,“旅行”,“税收”,“其他直接成本”等等。

这非常好,因为它不使用任何空间而不是int,当你查看源数据时,你不必链接查找表来知道值是什么。例如,引用行可能如下所示:

1 PartNumber $ 40 MTL
2 OtherPartNumber $ 29.99 SVC
3 PartNumber2 $ 150 TRV

使用int来表示类别然后在所有行上链接1,2,3要容易得多 - 你的数据就在你面前,而且性能似乎根本没有受到影响(不是我真的经过了测试。)

就真正的问题而言......我喜欢RowGUID uniqueidentifiers。我不是百分之百,但不是所有的行都有内部的RowGuid吗?如果是这样,那么使用RowGuid实际上会占用比int更少的空间(或其他任何东西。)我所知道的是,如果它足够好M $在GreatPlains中使用那么它对我来说已经足够了。 (我应该躲?)

哦,我使用GUID的另一个原因 - 我使用分层数据结构。也就是说,我有一个表'Company'和一个表'Vendor',其中主键匹配。但我也有一个'制造商'表,也'继承'公司。供应商和制造商共有的字段不会出现在这些表中 - 它们出现在公司中。在这个设置中,使用int比Guids更痛苦。至少,您不能使用身份主键。

每当我信任他们时,我都喜欢自然键。我愿意支付一个小的性价格,以便使用对主题专家有意义的密钥。

对于描述实体的表,应该有一个简单的自然键,以与主题人员相同的方式识别各个实例。如果主题没有其中一个实体的可信标识符,那么我将使用代理键。

对于描述关系的表,我使用复合键,其中每个组件引用参与关系的实体,因此引用实体表中的行。同样,使用复合键的性能损失通常很小。

正如其他人所指出的那样,术语“主键”指的是“主键”。有点误导。在关系数据模型中,使用的术语是“候选键”。单个表可能有几个候选键。从逻辑上讲,每一个都和另一个一样好。选择其中一个为“主要”并通过该键进行所有引用只是设计师可以做出的选择。

Guids.period。

如果您需要扩展或需要通过其他方式分配主键,他们将成为您的朋友。您可以为其他所有内容添加索引。


更新以澄清我的陈述。

我曾经在很多不同类型的网站上工作过。从小型单一服务器交易到支持多个数据库和Web服务器的大型服务器。肯定有一些应用程序可以自动增加整数作为主键。但是,那些不适合我的工作模式。

使用GUID时,您可以在任何地方生成ID。它可以由远程服务器,您的Web应用程序,在数据库本身内生成,甚至可以在多主机情况下的多个数据库中生成。

另一方面,只能在主数据库中安全地生成自动递增的INT。同样,如果你的应用程序与那个支持数据库服务器密切相关,那么可能可以,并且扩展不是你所关心的。

当然,使用GUID意味着您必须每晚重建索引流程。但是,如果您使用的是除自动增量INT之外的任何其他内容,则无论如何都应该这样做。哎呀,即使将INT作为主要内容,您可能还需要重新生成其他索引来处理碎片。因此,使用GUID并不会完全添加其他问题,因为无论如何都需要执行这些任务。

如果您看一下较大的应用程序,您会发现一些重要的事情:它们都使用Base64编码的GUID作为密钥。原因很简单,GUID的使用使您可以轻松地扩展 out ,而在尝试扩展INT时可能会有很多跳跃。

我们最新的应用程序经历了一段时间的重插入,持续了大约一个月。之后,90%以上的查询都是报告选择。为了增加容量,我可以在这个大插入期间启动额外的数据库服务器;然后很容易将它们合并到一个DB中进行报告。试图用INT进行这项工作将是一场绝对的噩梦。

坦率地说,无论何时集群数据库或设置复制,数据库服务器都会要求您在桌面上拥有GUID。所以,如果您认为您的系统可能需要增长,那么选择一个好的系统。

无论你是否意识到,这都是一个复杂的主题。可能属于StackOverflow FAQ的部分。

我不应该在这里问什么样的问题?

避免提出主观,议论或需要进行深入讨论的问题。这是一个可以回答问题的地方!

多年来一直争论不休,并将继续争论多年。我看到的唯一一致的暗示是,答案在某种程度上是可以预测的,这取决于你是否要求OO人(GUID是唯一的方法!),数据建模者(自然键是唯一的方法!),或面向绩效的DBA(INT是唯一的方法!)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top