在我的团队的一个相当生气勃勃的讨论中,我被认为是大多数人喜欢的主键.我们有以下小组 -
Int/BigInt哪个自动增量是足够好的主键.
应该至少有3列构成主键.
Id,GUID和人类可读行标识符都应该区别对待.
什么是PK的最佳方法?如果你可以证明你的意见,这将是很棒的.上面有没有更好的方法?
编辑:任何人都有一个简单的样本/算法来生成可扩展的行的人类可读标识符?
如果您要在偶尔连接的应用程序的数据库之间进行任何同步,那么您应该使用GUID作为主键.这是一种调试的痛苦,所以除了这种情况,我倾向于坚持自动增量的整数.
自动增量int应该是您的默认值,不应使用它们是合理的.
我没有看到一个答案指出(我认为)真正的基本点 - 也就是说,主键是保证你不会在表中为同一个真实世界实体获得两个条目(如在数据库中建模).这种观察有助于确定主键的优点和选择.
例如,在(US)州名和代码表中,名称或代码可以是主键 - 它们构成两个不同的候选键,其中一个(通常是较短的 - 代码)被选为首要的关键.在函数依赖性理论(和连接依赖性 - 1NF到5NF)中,候选键是关键而不是主键.
对于反例,人名通常是主键的错误选择.有许多人以"约翰史密斯"或其他类似的名字命名; 甚至考虑到中间名(记住:不是每个人都有一个 - 例如,我没有),有很多重复的余地.因此,人们不会使用名称作为主键.他们发明了人工密钥,例如社会安全号码(SSN)或员工编号,并使用它们来指定个人.
理想的主键是短小,独特,令人难忘和自然.在这些特征中,唯一性是强制性的; 考虑到现实世界数据的限制,其余的必须弯曲.
因此,在确定给定表的主键时,您必须查看该表所代表的内容.表中的哪些列集或列集唯一标识表中的每一行?这些是候选键.现在,如果每个候选键由4列或5列组成,那么您可能会认为这些列太笨拙而无法制作好的主键(主要是基于短路).在这种情况下,您可能会引入代理键 - 人工生成的数字.通常(但不总是)一个简单的32位整数就足以代替密钥.然后,您将此代理键指定为主键.
但是,您仍必须确保其他候选键(对于代理键也是候选键,以及所选主键)都保持为唯一标识符 - 通常通过在这些列集上放置唯一约束.
有时,人们发现难以确定哪一行是独特的,但应该有一些事情要做,因为简单地重复一条信息并不会使它更加真实.如果你不小心并且确实得到两个(或更多)声称存储相同信息的行,然后你需要更新信息,则存在危险(特别是如果你使用游标),你将只更新一行而不是每一行,所以行不同步,没有人知道哪一行包含正确的信息.
在某些方面,这是一个非常强硬的观点.
在需要时使用GUID我没有特别的问题,但它们往往很大(如16-64字节),并且它们经常被使用.通常,一个非常好的4字节值就足够了.使用GUID,其中4字节值足以浪费磁盘空间,并且甚至减慢了对数据的索引访问速度,因为每个索引页的值更少,因此索引将更深,并且必须读取更多页面才能访问信息.
这只是一个宗教问题,因为人们寻求普遍的正确答案.你的团队和这个SO线程显示出如此多的分歧的事实应该是一个线索,在不同的情况下有充分的理由使用你描述的所有解决方案.
当表中没有其他属性或属性集适合于唯一地标识行时,代理键很有用.
在可能的情况下,自然键是首选,以使表更易于阅读.自然键还允许从属表中的外键包含实际值而不是代理ID.例如,当您需要存储state
(CA,TX,NY)时,您也可以使用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千万亿)行.
略有偏离主题,但我觉得有必要加入......
如果主键是GUID,请不要使其成为聚簇索引.由于GUID是非顺序的,因此几乎每次插入时数据都将重新排列在磁盘上.(哎呀.)如果使用GUID作为主键,它们应该是非聚簇索引.
我认为在"主要"键中使用"主要"一词是真正意义上的,具有误导性.
首先,使用"key"是表中必须唯一的属性或属性集的定义,
然后,拥有任何密钥服务于几个通常相互矛盾的目的.
将连接条件用作子表中与该父表有关系的一个或多个记录.(在这些子表中明确或隐式定义外键)
(相关)确保子记录必须在父选项卡中具有父记录; e(子表FK必须作为父表中的键存在)
增加需要快速查找表中特定记录/行的查询的性能.
通过防止表示相同逻辑实体的重复行插入表来确保数据一致性.(这通常称为"自然"键,应该包含相对不变的表(实体)属性.)
显然,任何非有意义的非自然键(如GUID或自动生成的整数)完全无法满足#4.
但通常,对于许多(大多数)表,可以提供#4的完全自然的键通常由多个属性组成,并且过宽,或者如此宽,以至于将其用于#1,#2或#3目的将导致不可接受性能后果.
答案很简单.使用两者.对其他子表中的所有Joins和FK使用简单的自动生成整数键,但要确保每个需要数据一致性的表(很少有表没有)具有备用的自然唯一键,以防止插入不一致的数据行. ..另外,如果你总是同时使用两者,那么所有反对使用自然键的反对意见(如果它改变了怎么办?我必须改变它被引用为FK的每个地方)都没有实际意义,因为你没有使用它. ..你只是在一个表中使用它,它是一个PK,以避免不一致的duplciate数据...
对于GUID,要非常小心地使用它们,因为在索引中使用guid可以软管索引碎片.用于创建它们的最常用算法将guid的"随机"部分放在最重要的位位置......这增加了对添加新行时常规索引碎片整理/重新索引的要求.
你不应该做的一件事是使用智能钥匙.这是一个关键,有关记录的信息在密钥本身编码,它最终会咬你.
我在一个地方工作,其中主键是帐户ID,它是字母和数字的组合.我不记得任何细节,但是,例如,那些特定类型的帐户将在600范围内,而另一种类型,从400开始.这很好,直到该客户决定要求两者工作类型.或者改变了他们所做的工作类型.
另一个地方,使用树中的位置作为记录的主键.所以会有如下记录.
Cat1.subcatA.record1 Cat1.subcatA.record2 Cat1.subcatB.record1 Cat2.subcatA.record1
当然,客户想要的第一件事就是在树中移动物品.整套软件在此之前就已经死了.
拜托,如果您正在编写我需要维护的代码,请不要使用智能密钥!