了解埃德加·F·科德如何用关系模型把数据变成表、键和规则——为推动 SQL 数据库成为支撑业务应用的基础奠定了道路。

最简单的说,关系模型把信息存为一组表(科德称之为“关系”),这些表可以通过共享值来关联。
一个表就是一个整齐的网格:
业务数据不会独立存在。一笔销售涉及客户、产品、价格、销售人员和日期——每项都会以不同速度变化并由不同团队负责。早期系统常把这些细节存放在紧耦合、难以更改的结构中,使得报表缓慢、修改风险高,“简单问题”异常昂贵。
关系模型提出了更清晰的做法:为不同概念保留独立表,在需要答案时再把它们连接起来。与其在每条发票记录上复制客户详情,不如把客户只存一处,并在发票中引用它们。这减少了矛盾(同一客户的两种拼写)并使更新更可预测。
通过强调定义良好的表与连接规则,该模型设定了新的期望:数据库应该在规模增长时帮助防止不一致——尤其是当多人和多系统同时写入时。
科德的模型并不是查询语言,但它启发了查询语言的出现。如果数据存在于相关表中,就需要一种标准方法来:
这条路径导致了 SQL,把模型变为一种实用方式,让日常团队能对业务数据提出问题并得到可重复、可审计的答案。
在关系模型出现之前,许多组织把重要信息存放在文件里——通常是每个应用一个文件。工资单有自己的记录,库存有另一个,客户服务又有另一份“客户”版本。每个系统各自为政,这种孤立带来可预测的痛点。
早期数据处理通常建立在自定义文件格式和为单一目的编写的程序之上。数据结构(每个字段在哪、记录如何排序)与读取它的代码紧密绑定。这意味着即便是小的变更——添加字段、重命名产品类别、改变地址格式——也可能需要重写多个程序。
因为团队无法轻易共享单一真实来源,他们就复制数据。客户地址可能出现在销售文件、发货文件和账单文件中。
当地址变更时,每份副本都要更新。如果漏掉一个系统,就会出现不一致:发票寄错地方、发货延迟、支持人员在不同界面看到不同的“事实”。数据清理变成了反复出现的项目,而不是一次性修复。
业务用户仍会问业务问题——“哪些客户买了产品 X 后又退货?”——但是回答这些问题需要把从未设计来一起工作的文件拼接在一起。团队常常构建临时报表抽取,这又引入更多副本和更多不匹配的机会。
结果:报表周期缓慢,“快速问题”变成了工程工作。
组织需要被多个应用依赖的共享数据,减少不一致和重复劳动。他们也需要在不重建底层存储的情况下提出新问题。这一差距为科德的关键想法铺平了道路:以一致、与应用无关的方式定义数据,使系统能在不破坏其依赖真相的前提下演进。
埃德加·F·科德是英国计算机科学家,职业生涯大部分时间在 IBM 工作,研究组织如何高效地存储和检索信息。20 世纪 60 年代,大多数“数据库”系统更像是精心管理的文件柜:数据存放在刚性、预定义的结构中,改变这些结构常常意味着要重写应用程序。这种脆弱性在业务增长和需求变化时令团队沮丧。
1970 年,科德发表了一篇题目很长的论文——《A Relational Model of Data for Large Shared Data Banks》——提出了一个令人惊讶的简单想法:把数据表示为相关表,并使用一组形式化的操作来查询和组合它们。
高层来看,该论文主张:
科德把他的提议建立在数学(集合论和逻辑)上。这不是学术炫技——它为数据库设计提供了清晰、可检验的基础。有了形式化模型,你可以推理查询是否正确、两个查询是否等价,以及如何在不改变结果的情况下优化执行。对业务软件而言,这意味着随着系统扩展和演进,惊喜会更少。
当时许多系统依赖层次或网络模型,开发者需要沿预定义路径“导航”数据。科德的做法挑战了这种思维,认为数据库应该承担繁重工作。应用不应知道存储布局;它们应描述所需结果,由数据库找出高效的执行方式。
这种关注点分离为 SQL 以及能够在多年产品需求变更中存活的数据库奠定了基础。
科德的关系模型从一个简单思想开始:把事实存为关系——大多数人称之为表——但把它们当作一种精确描述数据的方式,而不是“聪明的电子表格”。关系是一组关于业务关心事物的陈述:客户、订单、付款、产品、发货。
一个关系表示一种事实模式。例如,Orders 关系可能捕捉“一个订单有一个 ID、一个日期、一个客户和一个总额”。关键点是每个关系具有明确含义,每列都是该含义的一部分。
一行(科德称为元组)是该事实的一个具体实例:一笔特定的订单。在关系模型中,行没有固有的“位置”。第 5 行不特殊——重要的是值和定义它们的规则。
一列(一个属性)是关系中的一个特定属性:OrderDate、CustomerID、TotalAmount。列不仅仅是标签;它们定义了允许的值类型。
域是属性允许的一组值——比如 OrderDate 的日期、TotalAmount 的正数,或 Status 的受控代码列表(例如 Pending、Paid、Refunded)。域减少了歧义,防止像混用“12/10/25”格式或在数值字段里存“ N/A ”这样的细微错误。
“关系”指的是事实如何在关系之间连接(如客户到订单),使常见的业务任务——计费、报表、审计、客户支持——在不复制信息的情况下得以进行。
表格本身有用,但业务数据只有在能可靠连接事实时才有意义:哪个客户下了哪个订单?订单里有哪些商品?收了多少钱?键是使这些连接可靠的机制。
主键是一列(或若干列)的组合,其值能唯一标识一行。把它想象成行的“名牌”。重要的是稳定性:姓名、邮箱和地址会变,但内部 ID 不该变。
一个好的主键能防止重复或模糊记录。如果两个客户同名,主键仍能区分它们。
外键是存放另一张表主键的列。这是表示关系而不复制所有数据的方式。
例如,可以如此建模销售:
外键约束像护栏一样,阻止:
在实际中,键和约束让团队信任报表与工作流。当数据库执行关系约束时,计费、履约与客服中的错误更少——因为数据不会悄然漂移到不可能的状态。
规范化是关系模型防止数据随规模增长而发生矛盾的方式。当相同事实存放在多个地方时,很容易更新一处却忘了另一处。这就是为什么企业会出现发票寄到错误地址、报表不一致或某屏显示客户为“非活跃”,另一个却显示为“活跃”。
在实务层面,规范化减少常见问题:
它也避免 插入异常(在没有订单的情况下无法添加新客户)和 删除异常(删除最后一笔订单不小心删掉了客户的唯一信息)。
你不需要深奥理论就能把这些想法用好:
第一范式(1NF): 保持每个字段原子。如果一个客户有多个电话号码,不要把它们塞在一个单元格里;用单独的表(或单独的行)来存放,这样每个值都能被搜索和更新。\n\n第二范式(2NF): 如果表的身份依赖多个列(复合键),确保非键详情依赖于整个键。订单行应为该行存储数量和价格,而不是客户地址。\n\n第三范式(3NF): 把“次要事实”移到别处。如果表同时存 CustomerId 和 CustomerCity,城市通常应存在客户表中,而不是复制到每个订单。
更高的规范化通常意味着更多表和更多连接。这提高了一致性,但也会让报表更复杂,有时影响性能。许多团队会对核心实体(客户、产品、发票)采用 3NF,然后针对读取频繁的仪表盘有选择地进行反规范化——同时保留通过主键/外键关系强制的权威真相源。
关系代数是关系模型背后的“数学”——一小组精确的操作,用来把一组行(表)变换成另一组行。
这种精确性很重要。如果规则清晰,那么查询结果也就清晰。你可以预测过滤、重塑或合并数据时会发生什么——而不依赖未记录的行为或手动导航。
关系代数定义了可以组合的构建块。其中三个最重要的:
Select(选择):挑选你想要的行。
示例:“仅上个月的订单”或“仅法国的客户”。你保留相同的列,但减少了行数。\n\n- Project(投影):挑选你想要的列。
示例:"显示客户姓名和邮箱"。你在逻辑上保留相同的行,但去掉不需要的列。\n\n- Join(连接):合并来自不同表的相关事实。
示例:"把客户详情附到每个订单",使用共享标识符(如 customer_id)。输出是一个新表,每行将分开存储的字段组合在一起。
业务数据天然地按主题拆分:客户、订单、发票、产品、付款。那种拆分让每个事实只存一次(有助于避免不匹配),但也意味着答案常常需要把这些事实重新组合。
连接是执行这种重组合的正式方式,同时保持语义。与其把客户名复制到每个订单行(随后在拼写变更时处处修复),更好地是只存客户一次,报表时再进行连接。
因为关系代数被定义为对行集的操作,每一步的预期结果都有明确范围:
这是后来让 SQL 实用的概念支柱:查询成为一系列定义良好的变换,而非临时的数据抓取。
科德的关系模型描述了数据的含义(关系、键和操作),但并没有规定一种便捷的日常使用方式。SQL 填补了这一空白:它把关系思想变成一种可读的语言,供分析师、开发者和数据库产品共享。
SQL 受关系代数启发,但并不是科德原始理论的完美实现。
一个关键差异是 SQL 如何处理缺失或未知值。经典关系理论基于二值逻辑(真/假),而 SQL 引入了 NULL,导致三值逻辑(真/假/未知)。另一个差异:关系理论处理集合(无重复),但 SQL 表通常允许重复行,除非你显式禁止它们。
尽管有这些差异,SQL 保留了核心承诺:你描述想要的结果(声明式查询),数据库负责找出执行步骤。
科德在 1970 年发表了奠基论文。20 世纪 70 年代,IBM 构建了早期原型(特别是 System R),证明关系数据库在实际负载下能够表现良好,并且可以把高级查询语言编译为高效的执行计划。
与此同时,学术界和商业界推动了 SQL 的发展。到 1980 年代后期,SQL 标准化(ANSI/ISO)使得厂商能够在通用语言上趋同——尽管每个产品都有自己的扩展。
SQL 降低了提问的成本。团队不再为每个报表编写定制程序,而可以直接用查询表达问题:
GROUP BY 按地区和月份统计销售对业务软件而言,SQL 的连接与聚合组合是一次突破。财务团队可以对发票与付款进行核对;产品团队可以分析转化漏斗;运维团队可以监控库存与履约——所有这些都通过查询相同的共享结构化数据模型完成。
这种可用性是关系模型从研究领域走向日常工具的一个重要原因。
业务系统的成败建立在信任之上。数据库仅仅“存储数据”是不够的——它必须在多人同时使用系统时仍然保持正确的余额、准确的库存计数和可信的审计轨迹。
事务把一组更改归为一次业务操作。想想:"转账 100 美元"、"发货"或"执行一次工资发放"。这些操作会触及多张表与多行。
关键思想是要么全部成功,要么全部不发生:
这就避免了钱从一个账户离开但未到达另一个账户,或库存减少却未记录订单的情况。
ACID 是业务依赖的担保缩写:
约束(如主键、外键、检查约束)阻止无效状态被记录。事务确保跨表的相关更新一并到达。
在实践中:一个订单被保存、其订单行被保存、库存被扣减、审计日志写入——要么这一切都发生,要么都不发生。正是这种组合让 SQL 数据库能够在规模上支撑严肃的业务软件。
SQL 数据库并非因为“流行”而胜出——它们契合了大多数组织的思维与工作方式。公司里充斥着重复且结构化的事物:客户、发票、产品、付款、员工。每项都有一组明确的属性,并以可预测的方式相互关联。关系模型与这种现实高度吻合:一个客户可以有多笔订单,订单有明细,付款与发票对账。
业务流程以一致性和可追溯性为基础。当财务问“哪些发票未付?”或客服问“该客户使用的是哪种方案?”,无论哪个工具或团队提问,答案都应一致。关系型数据库旨在让事实只存一次并被各处引用,从而减少导致代价高昂返工的矛盾。
随着 SQL 的普及,围绕它形成了生态系统:报表工具、BI 仪表盘、ETL 管道、连接器与培训。这种兼容性降低了采用成本。如果你的数据存放在关系数据库中,通常较容易接入常见的报表与分析工作流,而无需大量定制胶水代码。
应用快速演进——新功能、新界面、新集成。设计良好的模式就像一份持久契约:即便服务和页面变化,核心表与关系保持数据含义稳定。这种稳定性是 SQL 数据库成为业务软件可靠中心的重要原因。
模式不仅组织数据——它们也澄清角色。团队可以就什么是“客户”、哪些字段为必填、记录如何连接达成一致。借助主键与外键,职责变得明确:谁创建记录、谁能更新、以及哪些内容在全公司范围内必须保持一致。
关系数据库凭借可预测与安全赢得了一席之地,但并不适合所有工作负载。许多对 SQL 系统的批评其实是对把一把工具用于所有工作的批评。
关系模式是一份契约:表、列、类型与约束定义了什么是“有效数据”。这对共享理解很棒,但在产品仍在快速演进时会让团队变慢。
如果你每周都在推出新字段,协调迁移、回填和部署会成为瓶颈。即使有良好工具,模式变更也需要规划——尤其是在表很大或系统必须 24/7 在线时。
“NoSQL”并非对关系思想的否定,而是对特定痛点的回应:
这些系统中许多为获取速度、灵活性或分布性而牺牲了严格一致性或丰富的连接能力。
大多数现代技术栈是多范式的:对核心业务记录使用关系数据库,另配事件流、搜索索引、缓存或文档存储来处理内容和分析。关系模型仍然是事实来源,而其他存储负责只读或专门的查询场景。
选择时关注:
一个好的默认是把 SQL 用于核心数据,只有在关系模型明确成为瓶颈时才引入替代品。
科德的关系模型不仅是历史——它是一套习惯,使业务数据更易于信任、变更与报表。即便你的应用使用了多种存储系统,关系式思维仍是“记录系统”(订单、发票、客户、库存)的强默认选择。
先把业务关心的名词建模为表(Customers、Orders、Payments),再用关系把它们连接起来。
几个避免后续痛苦的规则:
phone1, phone2, phone3)。\n- 把“事实”和“标签”分开存:存数值金额和货币代码,而不是格式化字符串。在把这些原则变成产品时,使用能保持模式意图和应用代码一致的工具会很有帮助。例如,Koder.ai 可以从聊天提示生成 React + Go + PostgreSQL 应用,这让原型化规范化模式(表、键、关系)变得容易——同时仍把数据库作为事实来源,并在你准备好完全掌控时导出源代码。
如果你的数据需要强正确性担保,问自己:
如果这些的回答经常为“是”,关系型数据库通常是最简洁的路径。
“SQL 不能扩展”这是过于笼统的说法。SQL 系统有多种扩展方式(索引、缓存、只读副本、必要时分片)。大多数团队在真正触及数据库极限之前,先遭遇建模与查询问题。
“规范化让一切变慢”也不完全正确。规范化减少异常;性能通过索引、查询设计和在有测量依据时的选择性反规范化来管理。
科德给了团队一份共享契约:把数据安排为相关表,用定义良好的操作来操纵,并用约束来保护它。正是这份契约,让日常软件能在多年演进中仍回答诸如“发生了什么、何时发生、为什么发生?”这类基本问题。
关系模型把数据存为表(关系),包含:
它的关键好处是不同的表可以通过共享标识符关联,这样每个事实只存一次,按需重组合并用于报表和工作流。
基于文件的系统把数据布局紧耦合到应用代码中,导致实际问题:
关系数据库把数据定义与单一应用解耦,使跨系统查询变得常规和可靠。
**主键(PK)**唯一标识表中的每一行,且应在时间上保持稳定。
实用建议:
customer_id),不要用会变的字段如邮箱做主键。**外键(FK)**是一个列,其值必须对应另一个表的主键。它让你在不复制整条记录的情况下表示关系。
示例模式:
orders.customer_id 引用 customers.customer_id启用外键约束后,数据库可以防止:
规范化的目标是把每个事实尽可能只存一次,以减少不一致。它能防止:
一个常见做法是对核心实体目标做到 3NF,只有在有测量到的性能或查询理由时才选择部分反规范化。
1NF 的一个好规则是:每个字段只存一个值。
如果你把 phone1、phone2、phone3 放在同一表,应改为相关表:
customer_phones(customer_id, phone_number, type)这样便于搜索、校验和更新电话号码,避免“缺失列”类的问题。
关系代数定义了关系查询背后的核心操作:
你无需每天写关系代数,但理解这些概念能帮助你推理 SQL 的结果并避免在连接时意外产生重复数据。
SQL 通过提供一种声明式的查询方式,把关系的概念变为可用工具:你描述想要的结果,数据库负责选择执行计划。
关键实用收益:
GROUP BY)尽管 SQL 并非 Codd 理论的“完美”实现,它保留了核心工作流程:在相关表上进行可靠查询。
SQL 与“纯”关系模型在几个方面不同:
NULL 引入了三值逻辑(真/假/未知),影响筛选和连接的行为。实际使用中,你应对 NULL 的处理保持谨慎,并在关键场景下强制唯一性。
当你需要对共享业务记录的强一致性时,优先选择关系型数据库。
实用清单:
如果以上经常为“是”,关系型数据库通常是最简单的路径。只有在明确需要灵活数据形状、高度分布或专门查询(搜索/图)时,才考虑 NoSQL 或专用存储——并保持清晰的记录系统。