主题
第 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 开会的第一个议题。