导读:本期聚焦于小伙伴创作的《SQL范式是什么?数据库设计为什么要遵循范式原则》,敬请观看详情。为什么同一张订单表在业务膨胀后会出现更新异常和冗余数据?根本原因在于建表时忽略了范式约束。SQL范式是一组衡量关系模型结构化程度的规则,从第一范式到第三范式逐步消除重复组、函数依赖和传递依赖。遵循范式原则,能把客户信息、商品信息从订单主表中剥离,用外键关联,让插入、删除、修改操作互不干扰。反范式虽能提升查询速度,但会牺牲一致性。理解每层范式解决了什么具体问题,才能在小项目快速迭代与大数据量维护成本之间做对取舍。

SQL范式是关系型数据库设计中用来规范表结构的一组理论准则,目的是通过减少数据冗余和避免操作异常,让数据存储更合理。范式从低到高分为第一范式、第二范式、第三范式乃至BC范式、第四范式等,每一层都在前一层基础上提出更严格的约束。实际开发中并不需要盲目追求最高范式,而是结合业务读写比例来权衡。

SQL范式是什么?数据库设计为什么要遵循范式原则

第一范式:原子性约束

第一范式(1NF)要求表中的每一个字段都是不可再分的基本数据项,也就是说同一列不能存放多个值或用逗号拼接的字符串。很多新手在存用户电话时会写“13800000000,13900000000”,这就违反了1NF,因为电话列还能继续拆分。满足1NF后,才能使用关系型数据库提供的索引、约束等能力对单列做精确操作。

下面这段建表语句展示了违背与遵循1NF的差别。左侧把爱好存成一个字符串,右侧拆成独立行,通过关联表表达多对多关系。

-- 违反1NF的写法
CREATE TABLE user_bad (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  hobbies VARCHAR(200) -- 值类似 "篮球,音乐,阅读" 违反原子性
);

-- 遵循1NF的写法
CREATE TABLE user_good (
  id INT PRIMARY KEY,
  name VARCHAR(50)
);
CREATE TABLE user_hobby (
  user_id INT,
  hobby VARCHAR(50),
  PRIMARY KEY(user_id, hobby)
);

第二范式:消除部分函数依赖

第二范式(2NF)建立在第一范式之上,针对复合主键的表,要求非主键字段必须完全依赖于整个主键,而不能只依赖主键的一部分。如果一张成绩表用(学生ID,课程ID)做联合主键,但学生姓名只依赖学生ID,那就出现了部分依赖,导致增删课程时学生姓名被重复存储。

解决方式是把只依赖部分主键的字段拆到独立表中。如下代码将学生信息剥离,成绩表只保留和课程相关的外键与分数,这样新增一门课不需要复制学生姓名,也避免了修改姓名时要改多行的风险。

-- 违反2NF
CREATE TABLE score_bad (
  student_id INT,
  course_id INT,
  student_name VARCHAR(50),
  score INT,
  PRIMARY KEY(student_id, course_id)
);

-- 遵循2NF
CREATE TABLE student (
  id INT PRIMARY KEY,
  name VARCHAR(50)
);
CREATE TABLE score (
  student_id INT,
  course_id INT,
  score INT,
  PRIMARY KEY(student_id, course_id),
  FOREIGN KEY(student_id) REFERENCES student(id)
);

第三范式:消除传递函数依赖

第三范式(3NF)要求非主键字段不能依赖于其他非主键字段,即消除传递依赖。比如员工表里有部门ID和部门名称,部门名称依赖部门ID,而部门ID依赖员工ID,那么部门名称就是通过部门ID传递依赖于主键,这会造成部门改名时所有员工记录都要更新。

把部门信息独立成表,员工表只保留部门ID外键,就满足了3NF。下面的示例体现了这种拆分如何让部门数据只维护一处。

-- 违反3NF
CREATE TABLE emp_bad (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  dept_id INT,
  dept_name VARCHAR(50) -- 依赖dept_id,传递依赖
);

-- 遵循3NF
CREATE TABLE department (
  id INT PRIMARY KEY,
  name VARCHAR(50)
);
CREATE TABLE employee (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  dept_id INT,
  FOREIGN KEY(dept_id) REFERENCES department(id)
);

范式原则的实践权衡

严格遵循范式能降低写入异常和冗余,但在报表类查询中常需要多表关联,带来性能开销。此时可适当反范式,比如订单列表冗余用户昵称,用空间换时间。判断标准很简单:如果某字段修改频率低且被高频读取,冗余它通常比每次关联更划算。

数据库范式不是教条,而是帮我们看清数据之间依赖关系的工具。小系统从3NF起步,遇到慢查询再局部反范式,是多数团队稳妥的做法。理解每层范式解决了什么异常,比死记定义更有价值。

SQL范式数据库设计范式原则修改时间:2026-08-09 22:24:24

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。