数据库设计:不只是在学技术,是在重塑思维方式
我大学的时候觉得数据库设计就是背三大范式,考试能写出 ER 图就算过关。后来工作了才发现,数据库设计教给我的根本不是 SQL 怎么写——是一种看待数据的方式。这种东西渗透到你用 Excel、设计系统、甚至日常决策的习惯里。
这篇文章不讲数据库设计的细节(那能写一本书),只是想让你知道:学它到底能给你带来什么,以及不学会让你错失什么。
学过 vs 没学过:数据库使用上的鸿沟
先看两个真实场景。
场景一:设计一个电商订单表
没学过数据库设计的人会这样干:
-- 一张表塞所有东西
CREATE TABLE orders (
id INT,
customer_name VARCHAR(100),
customer_phone VARCHAR(20),
customer_address VARCHAR(500),
product_name VARCHAR(200),
product_price DECIMAL(10,2),
product_category VARCHAR(50),
quantity INT,
total_amount DECIMAL(10,2),
order_time DATETIME,
delivery_company VARCHAR(100),
delivery_number VARCHAR(50),
notes TEXT
);
看着好像也能用。现在我问你三个问题:
- 同一个客户的地址信息在两个订单里重复了,客户搬了家,你怎么改?逐条订单去更新。
- 一个产品降价了,历史订单里的 product_price 也跟着变了——数据失真了。
- 某个产品被删除了,所有关联它的订单记录里 product_name 变成了一堆"未知商品"。
这就是没学过数据库设计的人典型的思路:把数据库当 Excel 用,一张表存所有,字段随便加。
学过数据库设计的人会这样干:
-- 分表,消除冗余
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(100),
phone VARCHAR(20)
);
CREATE TABLE customer_addresses (
id INT PRIMARY KEY,
customer_id INT REFERENCES customers(id),
address VARCHAR(500),
is_default BOOLEAN
);
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(200),
price DECIMAL(10,2),
category VARCHAR(50)
);
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_id INT REFERENCES customers(id),
address_id INT REFERENCES customer_addresses(id),
total_amount DECIMAL(10,2),
order_time DATETIME,
delivery_company VARCHAR(100),
delivery_number VARCHAR(50)
);
CREATE TABLE order_items (
id INT PRIMARY KEY,
order_id INT REFERENCES orders(id),
product_id INT REFERENCES products(id),
product_name_snapshot VARCHAR(200), -- 快照!保留下单时的产品名
product_price_snapshot DECIMAL(10,2), -- 快照!保留下单时的价格
quantity INT
);
看出区别了吗:
- 客户搬家了,改
customer_addresses一条记录就行,历史订单不受影响。 - 产品价格变了,历史订单的
product_price_snapshot不受影响——这是下单那一刻的价格快照。 - 产品下架了,但历史订单里的
product_name_snapshot还在——你能知道当时卖的是什么。
这些决策背后的思考不是"SQL 语法熟不熟"的问题,是数据独立性、冗余控制、历史完整性这些概念在你脑子里有没有。
场景二:加一个新功能
没学过的做法:
老板说:“我们要支持一个订单包含多个收货地址”。
没学过的人会怎么做?在 orders 表里加新字段——address1、address2、address3。加完发现配送费也要分地址算,再加 delivery_fee1、delivery_fee2、delivery_fee3。
下次老板说"支持一个产品送到多个地址",又得加字段。表结构开始腐烂。
学过的做法:
直接拆一张 order_deliveries 表出来,订单和配送地址是多对多关系。不管以后需求怎么变,表结构不用动。
这种思维方式可以总结为一句话:预见到变化,把"可能变的部分"单独抽出来,不给"稳定部分"添麻烦。
数据库设计思维如何渗透到 Excel
好多人觉得数据库设计是 DBA 的事,跟自己没什么关系。但你不搞数据库,总要搞 Excel 吧?
看看同样一份数据,两种思维方式的差异有多大。
案例:管理部门的项目跟踪表
没学过数据库设计的人做的 Excel:
| 项目名称 | 负责人 | 负责人手机 | 参与人1 | 参与人2 | 参与人3 | 开始日期 | 结束日期 | 状态 | 备注 |
|---|---|---|---|---|---|---|---|---|---|
| X项目 | 张三 | 138xxxx | 李四 | 王五 | 1月1日 | 3月1日 | 进行中 | xxx | |
| Y项目 | 李四 | 139xxxx | 张三 | 赵六 | 王五 | 2月1日 | 4月1日 | 进行中 | xxx |
当需要统计"王五参与了几个项目"时——你得在一行一行里肉眼找,或者写个复杂的公式去 参与人1、参与人2、参与人3 三列里搜。
当某天新增了 参与人4——之前的公式全要改。
学过数据库设计的人做的 Excel:
分成两个 Sheet。
Sheet 1:项目表
| 项目ID | 项目名称 | 开始日期 | 结束日期 | 状态 |
|---|---|---|---|---|
| P001 | X项目 | 1月1日 | 3月1日 | 进行中 |
| P002 | Y项目 | 2月1日 | 4月1日 | 进行中 |
Sheet 2:人员表
| 人员 | 所属项目 | 角色 |
|---|---|---|
| 张三 | P001 | 负责人 |
| 张三 | P002 | 参与人 |
| 李四 | P001 | 参与人 |
| 李四 | P002 | 负责人 |
| 王五 | P001 | 参与人 |
| 王五 | P002 | 参与人 |
| 赵六 | P002 | 参与人 |
现在"王五参与了几个项目"——选中 王五 那几行,看 所属项目 有几个不同的值。三秒搞定。
加了新的人——在人员表最后新增一行,什么都不用改。
你看,这就是数据库设计的"关系"思维在日常工具里的体现。没学过的人把所有数据堆在一起,后面灵活性问题全部暴露。学过的人一开始就把实体拆分开,每个实体只管自己的数据,互不干扰。
再举一个更生活化的例子
你平时有没有这样的经历:
- 在淘宝、京东上填了无数次同样的收货地址
- 在携程上反复输入乘机人信息
- 在银行 App 里每次都重新输一遍银行卡号
这些体验背后是同一个思维——这些系统的设计者,起初把"用户信息"和"订单信息"绑死在一起了,而不是把它们当作独立的实体。
数据库设计里这叫"实体独立性"。用户是用户,订单是订单,地址是地址。它们关联但不融合。懂了这一点,你做任何数据相关的设计都会下意识注意到"哪些东西应该独立存在"。
这种思维的价值远超出技术
数据库设计的核心训练不是 SQL、不是范式、不是索引优化。是下面这四种能力:
第一,拆解能力。 你能把一个复杂的东西分解成互不重叠、互相独立的单元。这跟编程里的模块化思维相通,跟管理里的分工思维也相通。
第二,关系建模能力。 你能在看似不相关的东西之间建立联系。用户和订单是一对多,订单和产品是多对多,项目和人员是多对多。这些关系在你的脑子里不是模糊的——是清晰的数字。
第三,冗余敏感度。 你看一个 Excel 表格,本能地就能发现"这个字段重复了"“这个数据应该拆出去”。外行看到的是"一张表",你看到的是一堆潜在的维护噩梦。
第四,变化预判能力。 做设计的时候你已经在想:如果这个需求变了,我的结构能不能扛住。这不是多虑——这是工程素养。
这四种能力,学了数据库设计的人会自然获得。没学过的人可能要踩过很多坑、重构过很多次、骂过很多次"谁写的这破表"之后,才能慢慢悟出来。
最后
数据库设计不是一门"学完就完了"的技术课。它是一种思维方式,而且会渗透到你的工作习惯里。
你会发现:你做系统设计的时候,第一反应是画表结构而不是写代码。你用 Excel 的时候,脑子里自动在分 Sheet。你看到乱糟糟的数据的时候,本能地想把它规范化。
这种感觉,只学编程语言是给不了你的。学完数据库设计回头看,你会发现自己分析问题的角度变了——从"这行代码怎么写"变成了"这个数据应该怎么组织"。这是质变。