当前位置:  开发笔记 > 编程语言 > 正文

你觉得你的主键怎么样?

如何解决《你觉得你的主键怎么样?》经验,为你挑选了9个好方法。

在我的团队的一个相当生气勃勃的讨论中,我被认为是大多数人喜欢的主键.我们有以下小组 -

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

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

    Id,GUID和人类可读行标识符都应该区别对待.

什么是PK的最佳方法?如果你可以证明你的意见,这将是很棒的.上面有没有更好的方法?

编辑:任何人都有一个简单的样本/算法来生成可扩展的行的人类可读标识符?



1> Bramha Ghosh..:

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

自动增量int应该是您的默认值,不应使用它们是合理的.


至少90%的时间,不需要GUID并且浪费空间.
我认真地认为GUID是一种矫枉过正.从来没有需要将GUID作为我的主键.
或者,不是浪费空间并冒着与GUID发生冲突的风险,而是制作原始主键和小标识符的复合键,其中每个同步源的小标识符都不同.
我工作的商店使用GUID来处理所有事情,即使公共标识符可用,如ISO国家或语言代码.甚至当布尔或`CHAR(1)`已经足够时,就像'性'一样.不用说,与之合作是一场噩梦.
GUID不是必需的,只需将步骤更改为10或20,或者将来需要将许多服务器同步.
这确实是正确答案,GUID = Global Unique IDentifier.这是你想要的PK不是吗?在全球范围内识别一条数据?
@stephbu:SQL Server函数newsequentialid()解决了索引碎片问题,但如果你不是绝对需要全局唯一性,那么24字节仍然有点过多.请参阅http://msdn.microsoft.com/en-us/library/ms189786.aspx.
使用GUIDS作为PK会增加很多开销:http://www.sqlskills.com/BLOGS/KIMBERLY/post/GUIDs-as-PRIMARY-KEYs-andor-the-clustering-key.aspx

2> Jonathan Lef..:

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

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

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

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

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

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

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

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

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


关于具有美国州名的样本,我更喜欢单独的代理键,因为代码是您无法控制的.如果他们因任何原因应该改变你会遇到问题.
你的第一点是正确的.这个约束有一个名称.它被称为"实体完整性".EI要求每个实体都具有唯一的身份.主键通常满足此要求,除非使用自动编号.使用自动编号,除了自动编号外,您可以获得两行相同的行.这通常会违反实体完整性.

3> Bill Karwin..:

这只是一个宗教问题,因为人们寻求普遍的正确答案.你的团队和这个SO线程显示出如此多的分歧的事实应该是一个线索,在不同的情况下有充分的理由使用你描述的所有解决方案.

当表中没有其他属性或属性集适合于唯一地标识行时,代理键很有用.

在可能的情况下,自然键是首选,以使表更易于阅读.自然键还允许从属表中的外键包含实际值而不是代理ID.例如,当您需要存储state(CA,TX,NY)时,您也可以使用char(2)自然键而不是int.

在适当的地方使用复合主键.id当存在非常好的复合键时,不要不必要地添加" "代理键(在多对多表中尤其如此).每张表中三列密钥的授权绝对是无稽之谈.

当您需要在多个站点上保留唯一性时,GUID是一种解决方案.如果您需要主键中的值是唯一的,但不是有序的或连续的,它们也很方便.

INT与BIGINT:表对于主键需要 64位范围并不常见,但随着64位硬件的可用性增加,它不应该成为负担,并且更加保证您不会溢出.INT当然是较小的,所以如果空间非常宝贵,它可以带来轻微的优势.


@FD:我不同意你的明确声明,自1992年以来我一直在开发SQL数据库.但是,代理键最好能够保持不变.
我不同意一个人可能会这样做.自然键太可怕了.如果想要更改数据怎么办?哦,你不能.在复合自然键上编写连接是一件痛苦的事.将该组合密钥传递到所有相关表是一种浪费.
@Robert:阅读"ON UPDATE CASCADE".但是我得到你所说的,并且我同意最好在大多数时候使用代理键,因为属性可能会发生变化并且不是唯一的.

4> duffymo..:

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

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


他们改变了他们的链接,这里是更新的书签:http://database-programmer.blogspot.com/2008/09/comprehensive-table-of-contents.html

5> Andrew not t..:

我喜欢我的独特之处.



6> Robert C. Ba..:

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

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

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

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



7> Portman..:

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

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


这实际上并不准确.数据将按顺序插入,因为GUID的随机性可能最终会出现在整个表格的任何位置.如果没有空间,则会发生页面拆分,但肯定不会"在每次插入时重新排列在磁盘上"甚至不能关闭.

8> Charles Bret..:

我认为在"主要"键中使用"主要"一词是真正意义上的,具有误导性.

首先,使用"key"是表中必须唯一的属性或属性集的定义,

然后,拥有任何密钥服务于几个通常相互矛盾的目的.

    将连接条件用作子表中与该父表有关系的一个或多个记录.(在这些子表中明确或隐式定义外键)

    (相关)确保子记录必须在父选项卡中具有父记录; e(子表FK必须作为父表中的键存在)

    增加需要快速查找表中特定记录/行的查询的性能.

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

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

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

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

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



9> thursdaysgee..:

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

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

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

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

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

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


这并不意味着自然键很愚蠢.但好点.
推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有