不要使用业务键作为数据库主键

Mark Seemann这篇博客文章反对使用自然键作为数据库表中的主键,而是建议始终使用合成(人工)键。

什么是自然键
自然键(也称为业务键或领域键 )是数据库中一种唯一键,由存在并在数据库外部世界(即业务领域或论域)中使用的属性组成。[3]在关系数据模型中,自然键是超键,因此是关系中所有属性的 功能决定因素。

自然键有两个互补的用途:

  • 它为数据提供了唯一的标识方法
  • 它施加一条规则,特别是唯一性约束,以确保数据在信息系统中保持唯一性

自然键不同于代理键,后者在数据库之外没有任何意义,不基于现实世界的观察,也不旨在作为对所建模现实的陈述。因此,自然键提供了一定的数据质量保证,而代理键则没有。数据元素通常有多个键,其中任意数量的键可以是自然键或代理键。

原文观点:
我目前正在学习数据库和信息系统的本科课程。由于这门课程面向没有实际经验的学生,因此它明智地按照教学进度进行。为了教授数据库键,它从自然键开始。

从教学角度来看,这是有道理的,到目前为止,与我一起工作的年轻人现在提出使用自然键进行数据库设计。

我没有责怪任何人。你必须先学会爬,然后才能走路。

然而,这种情况让我思考以下问题:自然键是否是一个好主意?

让我们考虑一个例子。对于我们正在做的一个小项目,我们创建了一个世界 50 家最佳餐厅的数据库。我的同学建议采用这样的表格设计:

CREATE TABLE Restaurants (
year TEXT NOT NULL,
rank TEXT NOT NULL,
restaurantName TEXT NOT NULL,
cityName TEXT NOT NULL
);

当然,在这一点上,这个表格定义根本没有定义任何键。我对此并无怨言。毕竟,一个月前,学生们可能还没见过数据库表。

不过,根据课程设置,为 Restaurants 表定义一个由 restaurantName、cityName 和 year 组成的键是很自然的。假设名称和城市可以唯一标识一家餐馆。

在这个特殊的例子中,这个假设可能真的成立。到此为止。毕竟,数据集并不算大,而且对于该州中的餐厅来说,拥有可识别的名称非常重要。如果让我猜,世界上可能只有一家 Nobelhart & Schmutzig。

不过,一个好的软件架构师还是应该对基本假设提出质疑

  • 名字和城市是天然的关键吗?

很容易想象这不是。

  • 如果我们把关键字扩展到国家这个字段呢?

好吧,但如果我们在美国斯普林菲尔德开了一家名为 "China Wok "的餐馆呢?
很难说是独一无二的。

  • 如果再加上州呢?

可能还是不唯一的。

标识
确保唯一性只是自然键众多问题中的第一个。你可能很快就会得出结论,对于餐厅数据库来说,合成键可能是最好的选择。

那么 "自然 "的自然键呢?

  • 汽车底盘编号就是一个例子。这已经是一个不透明的数字,而且很可能来自某个数据库。
  • 那么个人身份号码呢?在丹麦,我们有 CPR 号码,据我所知,美国的社会安全号码也大致类似。

如果你正在设计的数据库已经包含了这样一个个人身份号码,你可能会倾向于使用它作为自然键。毕竟,它在其他地方已经是一个键了,所以可以保证是唯一的,不是吗?

  • 是的,这个身份号码可以唯一地识别一个人,但反过来就不一定了。
  • 一个人可能有不止一个识别码。至少当时间是一个因素时是这样。

例如,由于技术和历史原因,丹麦的 CPR 号码带有个人出生日期和性别等信息(按键不应该带有这些信息)。自 2014 年起,一项新的法律允许变性公民获得一个新的 CPR 号码,以反映他们所认为的性别。这样做的后果是,同一个人可能拥有不止一个 CPR 号码。也许不会同时拥有一个以上,但一生中肯定会拥有两个。

即使现有的键保证是唯一的,你也不能假定唯一性会导致双射。如果使用外部唯一键,就可能无法跟踪要跟踪的实体。

这不仅适用于人,也适用于汽车、自行车(也有底盘编号)、网卡等。

数据录入错误
最后,即使你已经找到了一个自然键,它可以保证是唯一的,并且可以跟踪你想要跟踪的实际实体,但还有一个反对在系统中使用外部定义键的理由:

  • 数据录入错误。

就拿我的汽车底盘编号来说吧:
虽然我住在哥本哈根,大部分时间都是步行或骑自行车在城里转悠,但我还是拥有一辆老爷车,以便在国内其他地方代步。在丹麦,汽车每隔一年就要接受一次强制性的官方检查,我一生中也经历过几次这样的检查。几年前,负责检查的机械师告诉我,我的汽车底盘编号有误。

这确实让我有点紧张,因为我买的是二手车,我突然担心事情并不像我想的那样。难道我无意中买了一辆赃车?

但机械师只是走到他的电脑前更正了错误。这时,一种不同的不安袭上心头。当你从事编程工作几十年后,你就会学会预见各种典型的故障模式。由于底盘编号是自然钥匙的一个明显候选项,我已经预料到更改这个编号要么被证明是不可能的,要么会产生各种连锁反应,最终导致官方记录不再承认这辆车是我的。

但事实证明,不管是谁制作了那款软件,他们都知道自己在做什么,因为机械师只是更改了底盘编号,仅此而已。现在这已经是五六年前的事了,我仍然拥有同一辆车,官方的所有权记录也从未出现过任何问题。

发现汽车底盘编号错误的机械师将其明确解释为笔误(数据输入错误)

经过几十年的编程生涯,我认识到数据迟早会出错。

  • 要么是笔误,
  • 要么是最终用户输入错误,
  • 要么是从外部系统导入时出现数据转换错误。
  • 甚至是同一系统内的数据转换错误,因为它要经历升级和迁移。

关键点:

  • 系统的设计应允许对数据进行更正。这包括外部键的更正,如底盘编号、政府 ID 等。
  • 这就意味着您不能在自己的系统中使用这些键作为数据库键

结论:
无论您认为自然键有多稳定,它都可能发生变化,从而导致更新异常和完整性问题。

自然键对于数据库设计来说从来都不是一个好主意,而应该始终使用数据库生成的合成(人工)键作为主键。

原文链接:https://www.jdon.com/74064.html

相关推荐

  1. 不要使用业务作为数据库

    2024-06-10 14:30:02       35 阅读
  2. Django使用UUID作为

    2024-06-10 14:30:02       57 阅读
  3. 数据库使用回填

    2024-06-10 14:30:02       53 阅读
  4. 如何在PostgreSQL正确的 使用UUID 作为

    2024-06-10 14:30:02       26 阅读
  5. uuid作为和自增的优缺点

    2024-06-10 14:30:02       35 阅读
  6. 数据表没有进行自关联

    2024-06-10 14:30:02       52 阅读
  7. 【MySQL】和外

    2024-06-10 14:30:02       68 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-10 14:30:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-10 14:30:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-06-10 14:30:02       87 阅读
  4. Python语言-面向对象

    2024-06-10 14:30:02       97 阅读

热门阅读

  1. C# WPF入门学习主线篇(十八)—— Border布局容器

    2024-06-10 14:30:02       14 阅读
  2. 爬山算法的详细介绍

    2024-06-10 14:30:02       28 阅读
  3. SSRF 漏洞实践:端口扫描与任意文件读取

    2024-06-10 14:30:02       32 阅读
  4. SpringBoot实现上传头像(查看头像)

    2024-06-10 14:30:02       30 阅读
  5. 模拟CAS算法案例

    2024-06-10 14:30:02       25 阅读
  6. DeepSpeed Autotuning

    2024-06-10 14:30:02       29 阅读
  7. 10-Eureka-服务注册

    2024-06-10 14:30:02       24 阅读
  8. 在docker容器中使用gdb调试python3.11的进程

    2024-06-10 14:30:02       29 阅读