Llo*_*ten 245 sql database sql-server relational
在设计表时,我养成了一个习惯,就是让一个列是唯一的,并且我制作了主键.这取决于要求以三种方式实现:
数字3将用于相当小的查找,主要是可能具有唯一静态长度字符串代码的读取表,或者诸如年份或其他数字的数字值.
在大多数情况下,所有其他表将具有自动递增整数或唯一标识符主键.
我最近开始使用没有一致行标识符的数据库,主键目前在各个列上进行聚类.一些例子:
这有一个有效的案例吗?我总是会为这些案例定义一个标识或唯一标识符列.
此外,还有许多表没有主键.这有什么正当理由?
我试图理解为什么桌子的设计原样,对我来说这似乎是一个很大的混乱,但也许有充分的理由.
第三个问题可以帮助我解释答案:在使用多列构成复合主键的情况下,这种方法与代理/人工密钥相比有特定的优势吗?我主要考虑的是性能,维护,管理等方面?
Log*_*ind 238
我遵循一些规则:
在代理与自然键上,我参考上面的规则.如果自然键很小并且永远不会改变,则它可以用作主键.如果自然键很大或可能改变,我使用代理键.如果没有主键,我仍然会制作代理键,因为经验显示您将始终将表添加到架构中,并希望您将主键置于适当的位置.
Ton*_*ews 89
自然诗句人工键是数据库社区中的一种宗教辩论 - 请参阅本文及其链接的其他文章.我既不赞成总是拥有人工钥匙,也不赞成永远不拥有它们.我会根据具体情况做出决定,例如:
无论何处使用人工密钥,您都应该始终在自然键上声明唯一约束.例如,如果必须,请使用state_id,但是最好在state_code上声明一个唯一约束,否则你肯定最终得到:
state_id state_code state_name
137 TX Texas
... ... ...
249 TX Texas
Run Code Online (Sandbox Code Playgroud)
WW.*_*WW. 25
只是对经常被忽视的事情做出额外评论.有时不使用代理键在子表中有好处.假设我们的设计允许您在一个数据库中运行多个公司(可能是托管解决方案,或者其他任何东西).
假设我们有这些表和列:
Company:
CompanyId (primary key)
CostCenter:
CompanyId (primary key, foreign key to Company)
CostCentre (primary key)
CostElement
CompanyId (primary key, foreign key to Company)
CostElement (primary key)
Invoice:
InvoiceId (primary key)
CompanyId (primary key, in foreign key to CostCentre, in foreign key to CostElement)
CostCentre (in foreign key to CostCentre)
CostElement (in foreign key to CostElement)
Run Code Online (Sandbox Code Playgroud)
如果最后一位没有意义,Invoice.CompanyId则是两个外键的一部分,一个是CostCentre表,另一个是CostElement表.主键是(InvoiceId,CompanyId).
在这个模型中,这是不可能的螺丝,并引用CostElement从一个公司和一个CostCentre从另一家公司.如果在CostElement和CostCentre表上使用了代理键,那么它就是.
搞砸的机会越少越好.
小智 22
我避免使用自然键有一个简单的原因 - 人为错误.尽管通常可以使用自然唯一标识符(SSN,VIN,帐号等),但它们需要人员正确输入它们.如果您使用SSN作为主键,有人会在数据输入过程中转换几个数字,并且不会立即发现错误,那么您将面临更改主键的问题.
我的主键全部由后台的数据库程序处理,用户从不知道它们.
Don*_*res 13
从各个领域制作主键没有问题,这是一个自然键.
您可以使用Identity列(与候选字段上的唯一索引关联)来生成Surrogate Key.
这是一个古老的讨论.在大多数情况下,我更喜欢代理键.
但没有任何借口可以缺少一把钥匙.
RE:编辑
是的,有很多争议:D
除了事实上它们是自然选择之外,我没有看到任何关于自然键的明显优势.你总是会想到Name,SocialNumber - 或类似的东西 - 而不是idPerson.
代理键是自然键具有的一些问题的答案(例如,传播变化).
当你习惯了代理时,它似乎更干净,更易于管理.
但最终,你会发现这只是一种品味 - 或心态 - .人们用自然键"思考得更好",而其他人则不然.
Pat*_*ins 11
表应始终具有主键.当它不是它应该是一个AutoIncrement字段.
有时人们会省略主键,因为它们会传输大量数据,并且可能会减慢(依赖于数据库)进程.但是,它应该在它之后添加.
有关链接表中的一些一条评论,这是对的,这是一个例外,但字段应该是FK保持完整,一些情况下,这些领域可能是主键太多,如果在链接复制未经授权...而是保持在一个简单形式,因为异常是编程中常见的东西,应该存在主键以保持数据的完整性.
除了所有这些好的答案之外,我只想分享一篇我刚读过的好文章,这是一场伟大的主要辩论.
只是引用几点:
在为每个表选择主键时,开发人员必须应用一些规则:
自然键(倾向于)违反规则.代理键符合规则.(你最好仔细阅读那篇文章,值得你花时间!)
以下是我在 25 年以上的开发经验后确定的经验法则。
主键由数据库用于优化目的,您的应用程序不应将主键用于识别特定实体或与特定实体相关的任何其他用途。
始终拥有一个单值主键使得执行 UPSERT 非常简单。
比多列索引更喜欢单列上的多个索引。
例如,如果您有一个两列键,则倾向于在每列上创建一个索引而不是创建一个两列索引。如果我们在名字 + 姓氏上创建一个多列键,我们就不能在不提供名字的情况下对姓氏进行索引查找。在两列上都有索引允许优化器在其中一列或两列上执行索引查找,而不管它们在 WHERE 子句中如何表达。
如果您的表很大,请探索根据最突出的搜索条件将表划分为多个段。
如果您的表中包含大量 Id 字段,请考虑删除除主键之外的所有表,该表具有 id (PK)、org_id(原始表的 FK)和 id_type 列。为新表上的所有列创建索引并将其与原始表相关联。通过这种方式,您现在可以仅使用单个索引对任意数量的 id 执行索引查找。
小智 7
模式中表的用途是什么?桌子钥匙的目的是什么?主键有什么特别之处?围绕主键的讨论似乎忽略了主键是表的一部分,并且该表是模式的一部分.表和表关系的最佳选择应该是驱动所使用的密钥.
表(和表关系)包含有关您要记录的信息的事实.这些事实应该是自足的,有意义的,易于理解的和不矛盾的.从设计角度来看,在模式中添加或删除的其他表不应影响相关表.必须存储仅与信息本身相关的数据的目的.了解表中存储的内容不应要求进行科学研究项目.为同一目的存储的事实不应存储多次.密钥是记录的信息的全部或一部分,它是唯一的,主密钥是专门指定的密钥,它将成为表的主要访问点(即,应选择它用于数据一致性和使用,而不仅仅是插入性能).
据说主键应该尽可能小.我会说钥匙应该只有必要的大小.应避免随意向表中添加无意义的字段.从随机添加的无意义字段中创建密钥甚至更糟,特别是当它破坏从另一个表到非主键的连接依赖性时.如果表中没有好的候选键,这是合理的,但如果用于所有表,这种情况肯定是架构设计不佳的标志.
还有人说,主键永远不应该改变,因为更新主键始终是不可能的.但更新与删除后跟插入相同.通过这种逻辑,您不应该从具有一个键的表中删除记录,然后使用第二个键添加另一个记录.添加代理主键不会删除表中另一个键存在的事实.如果其他表通过代理键依赖于该含义,则更新表的非主键可能会破坏数据的含义(例如,具有代理键的状态表,其状态描述已从"已处理"更改为"已取消" '肯定会破坏数据).永远不可能的是破坏数据的含义.
话虽如此,我很感激今天企业中存在的许多设计不良的数据库(无意义的代理键控数据损坏的1NF庞然大物),因为这意味着对于理解正确的数据库设计的人来说,有无数的工作量. .但在悲伤的一面,它确实有时让我感觉像西西弗斯,但我打赌他有一个401k(崩溃之前).远离博客和网站,以获取重要的数据库设计问题.如果您正在设计数据库,请查看CJ Date.你也可以参考Celko for SQL Server,但前提是你先嗤之以鼻.在Oracle方面,参考Tom Kyte.
如果可用,自然键通常是最好的.因此,如果datetime/char 唯一标识该行,并且这两个部分对该行有意义,那就太好了.
如果只是日期时间是有意义的,并且刚刚添加了char以使其唯一,那么您可能只需要使用标识字段.
对我而言,自然键和人工键是您在数据库中需要多少业务逻辑的问题.社会安全号码(SSN)就是一个很好的例子.
"我的数据库中的每个客户端都必须拥有SSN." Bam,完成后,将其作为主键并完成它.请记住,当您的业务规则发生变化时,您就会被烧毁.
由于我改变业务规则的经验,我自己不喜欢自然键.但如果你确定它不会改变,它可能会阻止一些关键连接.