构建逻辑模型
另有 28 种语言版本
English · Español · 日本語 · Português (Brasil) · Français · Deutsch · Italiano · 한국어 · Português (Portugal) · 繁體中文 · Bahasa Indonesia · Türkçe · Polski · Tiếng Việt · ไทย · Nederlands · العربية · עברית · Українська · हिन्दी · Русский · Svenska · Dansk · Norsk bokmål · Suomi · Español (México) · Français (Canada) · Deutsch (Schweiz)

第 3 个模块,共 6 个,属于 Data Architect 课程第 2 章为含义建模数据。每个模块都可以单独阅读。 上一篇:画出关系 · 下一篇:把数据放在该放的地方
**本模块回答的问题:**如何把一个概念模型变成一个逻辑数据模型?
概念模型告诉了我们 Steve Trucking 有什么,以及它们如何关联:零售合作伙伴和它们的配送中心,装货清单和配送,收货人,路线和停靠点,配送小组、卡车和配送小组分配。这足以和业务方进行一次非常有成效的对话。但最终我需要更多细节。关于一次配送,我们需要知道什么?是什么让一个配送中心不同于另一个?我们如何识别一位收货人?什么属于配送小组分配,而不属于配送小组或卡车?这些问题把我们从概念模型推向逻辑数据模型,而我们仍然还没有在构建 Salesforce。
坐下、别动、建模
Section titled “坐下、别动、建模 ”先回到狗。我们已经有了方框和连线。现在有两个新问题:关于每个事物我们知道什么,以及我们怎么把它们一个个区分开?
**什么在描述它?**一只狗有名字和出生日期。一位主人有姓名、电话号码和地址。一项技能有名称和难度。每个事实都放在它所描述的方框上。
然后是联接。Bella 坐下做得有多好,什么时候学会的:这是在描述 Bella 吗?不完全是;她有些技能做得比别的好。是在描述坐下吗?不是;每只狗坐下的样子都不一样。它描述的是 Bella 和坐下这一对,所以它属于狗狗技能:熟练程度和学会日期。这就是联接存在的原因:有些事实只属于这一对。
哪只狗是哪只?先试试名字。叫 Max 的狗多得是,所以名字不唯一。主人的电话号码?Marcus 的两只狗用的是同一个电话,人会换号码,而且那是某个人的个人数据,会被复制到每一个指向狗的系统里。芯片号看起来更好:它唯一,而且不会变。但一只新来的小狗可能还没植入芯片,而键不能是空的。所以芯片号保留下来,作为这只狗的另一个已知标识,而狗有了自己的狗狗 ID(Dog ID):一个只做一件无聊工作的编号,把一只狗和另一只区分开。
我们接下来要问 Steve Trucking 的,也是同样的问题;而名字、电话和芯片号各自不够格的理由,会变成我坚持多年的一条规则。
概念模型告诉我有什么;逻辑模型告诉我它作为数据意味着什么
Section titled “概念模型告诉我有什么;逻辑模型告诉我它作为数据意味着什么 ”拿卡车来说。关于一辆卡车,我需要知道什么?也许是它的车辆编号、VIN、品牌、型号、年款、车牌、当前里程和状态。这些是卡车的属性。
再看配送。也许是零售合作伙伴的订单号、配送日期、承诺的时间窗口、实际到达时间、状态,以及是否包含安装或拉走旧货。同样,这些是属性。
概念模型告诉我们配送是存在的。逻辑模型开始告诉我们,一次配送作为数据意味着什么。像卡车或配送这样一个简单的方框,背后可能代表一整组字段。
即便如此,在我们大多数的图里,方框仍然保持简单,原因有三。字段的数量会增长。字段很快会过时。而且每个字段都有一些很难在对象模型里展示的细节:它的 API 名称、标签、数据类型和长度。这些细节一定会被记录下来,只是不在第一个数据模型里。当展示几个关键字段确实有助于讲清楚问题时,我会画一个详细数据模型:一个聚焦的切面,只包含与要点相关的字段。
属性应当描述实体
Section titled “属性应当描述实体 ”看一个属性时,我会问一个简单的问题:**它描述的是什么?**卡车品牌显然描述的是卡车。但配送上的配送小组成员姓名呢?它们描述的是配送吗?还是描述的是一个配送小组,这个小组有一项配送小组分配,这项分配覆盖了这条路线,而这条路线包含了这个停靠点?
数据模型正是在这里开始暴露那些在屏幕上看起来完全合理的东西。一位调度员说:“我想在配送上看到配送小组的姓名。”这是一项合理的用户体验需求。但它不一定是要把配送小组的姓名存储在配送上的需求。这是两回事,我们会在讲规范化时再回到这一点。现在,先养成习惯,问一问**这个事实实际上描述的是哪样东西。**这个问题会帮你省去很多麻烦。
然后我们得谈谈唯一 ID
Section titled “然后我们得谈谈唯一 ID ”属性描述事物。但还有另一个问题要解决:我怎么知道哪个是哪个?
两位收货人都叫 John Smith。他们是同一个人吗?也许是,也许不是。名字不够用。地址呢?人会搬家。电话号码会变。邮箱地址会变。连零售合作伙伴的名字都可能变。
这就引出了键:让我们在模型中唯一识别某样东西的东西。多年来,我在这个领域形成了相当坚定的看法。对于一个标识符,我要求四点:
唯一。不变。无含义。绝不是 PII。
**唯一。**一个标识符必须恰好识别一样东西。如果两次配送可能有相同的值,它就不是一个可靠的配送标识符。名字通常不唯一,地址不一定唯一,电话号码会被共用。即使今天看起来唯一的值,一旦数据够多,也可能不再唯一。所以要问:**这里的两个会不会有相同的值?**如果答案是会,就要非常小心,别把它用作记录的唯一 ID。
**不变。**这一点常常被忽略。如果我们用名字来识别一个零售合作伙伴,而这个合作伙伴改了名,我们是得到了一个新合作伙伴吗?不是。业务实体还是同一个;只是它的一个属性变了。记录的唯一 ID 应当在它所识别的东西发生变化后依然有效,这就排除了名字、邮箱地址、电话号码、地址和用户名,不管我们刚开始构建系统时它们看起来多么方便。
**无含义。**第一次听到这一点会觉得奇怪。我为什么要让标识符没有含义?因为含义会变。想象有人构建了一个配送 ID,把配送中心、零售合作伙伴、配送日期和序号编进去:PHX-KEY-20261002-0042。看起来很聪明。然后收货人把时间改到了周五。我们要改标识符吗?如果不改,它就在对我们撒谎。如果改了,我们就因为配送的一个属性变了而改了它的唯一 ID,而每个存过旧 ID 的系统都刚刚跟丢了它。这个标识符想同时做两份工作:识别这次配送,并且描述它。我宁愿让属性去描述它,让标识符只做一份乏味的工作:**识别它。**乏味的标识符才是好标识符。
**绝不是 PII。**这一点很重要,所以我把它单独列出来。不要因为个人身份信息看起来唯一,就把它用作标识符。在 Steve Trucking,人们很容易想用电话号码来识别收货人。但键会被复制到系统需要连接记录的每一个地方:集成、导出、日志、回传给零售合作伙伴的状态文件、数据仓库、测试数据。把电话号码当作键,你就把收货人的个人数据散布到了整个架构中。
键还必须对每一条记录都存在:**绝不能为 null 或空白。**如果有些人不愿意、也不应该被要求给你某个值,那么这个值就不能当键。这就是为什么系统要签发自己的内部标识符,而个人数据,如果确实需要的话,就成为一个受保护的属性。
所以我的规则是:唯一、不变、无含义、绝不是 PII。
自然键和代理键
Section titled “自然键和代理键 ”做数据库的人对其中一些概念有专门的叫法。自然键是业务数据中本来就存在的:卡车的 VIN 就是个好例子。它不是我们的应用发明的,而且本身已经有含义。代理键是专门为识别记录而创建的;它不描述任何东西,只负责识别。
在大多数架构里,我更喜欢用代理键作为内部记录 ID,同时把重要的自然标识符作为属性保留下来。这并不是说自然标识符不好;它们往往极其重要。我只是不会自动把它们当作记录的唯一 ID。问一问:如果这个值被更正、重新格式化、替换、重复使用、缺失,或者来自不止一个源系统,会发生什么。一个看似简单的决定,正是在这里变成了架构决定。
一样东西可以有好几个有用的标识符
Section titled “一样东西可以有好几个有用的标识符 ”内部记录 ID 不一定是其他所有系统都使用的标识符。Steve Trucking 内部可能用一个生成的 ID 来识别一次配送。每个零售合作伙伴则用自己的订单号来识别同一次配送:Keystone 在它的 CSV 装货清单里,Redrock 在它的 API 里,Brightwave 在它的 EDI 报文里。而遗留调度工具 RouteDesk 里的八年历史,用的是 RouteDesk 自己的配送 ID。
这些标识符都很重要。我们需要保留它们并正确映射,因为状态更新必须以每个合作伙伴自己的编号回传给它。但它们不必都成为配送的唯一 ID。“它的 ID 是什么?”可以有不止一个答案,而架构师必须知道在哪种情境下哪个 ID 是权威的。我们会在讲主数据和集成时回到这一点。
关系依赖于唯一 ID
Section titled “关系依赖于唯一 ID ”现在回到我们画的那些线。一份装货清单列出若干配送。一位收货人接收若干配送。一个配送小组有若干配送小组分配。这些关系之所以成立,只是因为我们能可靠地识别两端的东西。
在 Steve Trucking,问题会在这里咬人。某个零售合作伙伴当天修改了装货清单:一个订单取消了,一件商品换了,一个新地址。如果我们不能凭合作伙伴的订单号,把修改后的那一行和已有的配送匹配起来,我们就会为同一台冰箱创建第二次配送,一个配送小组可能会上门两次。方框、属性、键和关系不是各自独立的概念,它们都是同一个模型的组成部分。
这时你可能会想:“Salesforce 会给每条记录一个 ID。”没错,我们会讲到。如果数据存在 Salesforce 里,每条记录都会得到一个 Salesforce 生成的 ID。它晦涩难读,所以我们通常还会提供一个人们能用的 ID 字段,比如配送编号 D-000184227,一个自动编号字段。人们常以为这个编号就是记录的 ID,但它不是:Salesforce ID 仍然在底层。外部系统或数据库,比如 Oracle 或 SQL Server,也有自己的唯一 ID。但架构最终可能包含 Salesforce、财务 ERP、Snowflake、Data 360、合作伙伴的系统,以及尚不存在的系统。逻辑模型描述的是业务数据,而不让每个决定都依赖于某一种技术。Salesforce 如何在物理上实现它,是后面的步骤。
架构师在这里决定什么
Section titled “架构师在这里决定什么 ”在把概念模型变成逻辑模型时,我要决定的是:
- 哪些属性真正描述了每个实体。
- 每个实体如何被唯一识别,以及这个标识符是否稳定到足以成为它的唯一 ID。
- 哪些业务标识符(合作伙伴订单号、遗留 ID)需要被保留和映射。
- 是否有敏感信息被用作了键。
- 关系是否通过可靠的唯一 ID 连接实体。
现在我们有了实体、关系、属性和唯一 ID:一个真正的逻辑数据模型的雏形。但仍然有一个问题。把完全有效的数据放错地方是非常容易的。这就是规范化登场的地方。
- Custom Field Types (opens in a new tab),Salesforce Help(英文,查阅日期 2026-10-09):自动编号为每条记录分配一个唯一编号,可设置显示格式,如前缀和前导零;它不是记录的 Salesforce ID。另见 Auto-Number Fields Are Not Always Sequential (opens in a new tab)(英文,查阅日期 2026-10-09)。
