Skip to content

第 5 章 把表设计好:关系、外键、索引

第一册第 3 章说过:设计表结构,就是想清楚"产品到底要记住什么"。这一章给你三件设计工具,从此 AI 建的表你不光看得懂,还评得动。

**工具一:一个事实只存一份。**先看反面教材:如果 certificates 表里直接存一列 owner_email,会怎样?用户改一次邮箱,他名下一千张凭证就要改一千处——漏掉一张,数据从此打架,而且你永远不知道哪份是真的。正解你在第三册第 8 章已经见过:certificates 只存 owner_id,邮箱只住在 users 表里,一处修改,处处生效。这条朴素的原则是整个数据库设计的地基(教科书叫它规范化,记住人话版就够)。

工具二:外键,让数据库替你守规矩。owner_id 这个"工号"不只是约定——建表时声明出来,数据库会强制它有效。看一张真实形状的建表语句,AI 迁移文件里的那些话,现在全能读了:

sql
create table certificates (
  id uuid primary key default gen_random_uuid(),
  owner_id uuid references users(id) not null,
  status text not null default 'draft',
  created_at timestamptz default now()
);

逐行读:primary key 是每行的身份证(uuid 是一种全球不重复的随机编号,默认自动生成);references users(id) 就是外键——从此想塞一个不存在的 owner_id,数据库直接拒收,它从"记录事实"升级成了"守护事实";not null 是"此列不许空着";default 是没填时的默认值。关系的形态顺带认全:一对多(一个用户多张凭证——外键放"多"的那边),多对多(凭证和标签互相多——需要一张中间表牵线),一对一(少见)。

**工具三:索引,书后的检索目录。**没有索引时,WHERE owner_id = ... 等于逐页翻完整本书;跑一句 create index on certificates(owner_id); 之后,等于直接翻书后目录。代价是写入稍慢、占点空间,所以只给"经常用来找"的列建——经验法:外键列和高频出现在 WHERE 里的列(主键自带,不用操心)。第 8 章你会看到:九成"越用越慢",最后都查到一条缺索引的查询头上。

三件工具合成一个习惯:以后让 AI 建表,需求里先让它回答三问——有哪些"东西"(表)?它们怎么相连(外键)?最常按什么找(索引)?三问入了需求,AI 的建表质量立刻上一个档。

出事时想起我

同一个信息在两处对不上——设计违反了"只存一份";数据越多越慢——查缺失的索引;删用户时报 violates foreign key constraint——那是数据库在守护事实:他名下还有凭证呢。别硬删,这属于"想清楚再动"的决策(级联删除是把双刃剑,动它之前叫人)。

关键领悟

好的表设计三句话——一个事实只存一份;关系交给外键,让数据库强制守护;常走的查找路径铺上索引。

试一试(安全档:只读)

打开 Supabase,把我们最重要的两三张表画成一张纸上关系图:方框是表,箭头是外键,箭头旁标上"一对多"。画不出的那根箭头,就是你下次和 AI 开会的第一个议题。

由 Charles Tao 与 Claude 协作写成——这本身就是这套书讲的工作方式。 · 许可