SQL 结构检查:哪里有问题
下面不是编出来的清单,而是左边这份结构的真实检查报告。编辑器的「检查」标签里看到的是同样的结果,其中不少还能一键修复。
输入schema.sql
CREATE TABLE user (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL,
balance FLOAT,
created_at TIMESTAMP NOT NULL
);
CREATE TABLE orders (
order_id INTEGER NOT NULL,
user_id INTEGER REFERENCES user (id),
total FLOAT NOT NULL,
placedAt TIMESTAMP
);- 判断为
PostgreSQL
错误 1警告 8提示 2
打开编辑器
脚本留在浏览器里:解析和生成都在您的机器上进行,不会上传到服务器。
发现了什么
关系两端类型不同
orders.user_id列与它引用的目标声明方式不同。有的数据库直接拒绝建键,其余则在每次连接时静默转换类型。
表没有主键
orders这样的行无法可靠定位:既不能只更新两条相同行中的一条,也无法被别处引用。复制和 ORM 也都假定存在主键。
外键没有索引
orders连接查询和删除父行时的检查都要走这一列。没有索引,每一次都是全表扫描。
外键允许为 NULL
orders.user_id有时这是有意的:关系可选。但更常见的是忘了写 NOT NULL,于是出现没有父行的数据。
名字是保留字
user每条查询里都得给它加引号。改名比记住这个例外更省事。
金额用了近似类型
user.balanceorders.totalFLOAT 和 REAL 只能近似存储数值:第一次除法之后金额就对不上了。金额应当用 NUMERIC 或 DECIMAL。
TIMESTAMP 没有时区
user.created_atorders.placedAt在 PostgreSQL 里这种列不保存时区,会被默默当作本地时间。服务器迁移或夏令时切换后数值就会错位——通常需要的是 timestamptz。
命名风格不统一
orders.placedAt模式里 snake_case 和 camelCase 并存。这里列出的是少数派风格的名字:统一它们比记住例外更省心。
没有写 ON DELETE
orders删除父行时子行怎么办交由数据库决定,默认情况下它会拒绝删除。如果这不是本意,最好明确写出来。