数据库设计:不只是在学技术,是在重塑思维方式

我大学的时候觉得数据库设计就是背三大范式,考试能写出 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
);

看着好像也能用。现在我问你三个问题:

  1. 同一个客户的地址信息在两个订单里重复了,客户搬了家,你怎么改?逐条订单去更新。
  2. 一个产品降价了,历史订单里的 product_price 也跟着变了——数据失真了。
  3. 某个产品被删除了,所有关联它的订单记录里 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 表里加新字段——address1address2address3。加完发现配送费也要分地址算,再加 delivery_fee1delivery_fee2delivery_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。你看到乱糟糟的数据的时候,本能地想把它规范化。

这种感觉,只学编程语言是给不了你的。学完数据库设计回头看,你会发现自己分析问题的角度变了——从"这行代码怎么写"变成了"这个数据应该怎么组织"。这是质变。

一名痴迷于计算机技术的学生~