这是我能想到的最简单的解释方法。想象一下,用户想要为一堆网页添加书签。有一个带有 UrlID 和实际 url 的 url 表。我希望用户有一个唯一的 UrlID 列表(但我不需要约束)和一个 32 位 int 值,例如纪元日期。我唯一关心的两件事是 1) 检查 UrlID 是否在此列表中 2) 获取整个列表并按日期(或第二个值)对其进行排序
如果有帮助,我预计不会超过 8K 书签,但很可能会 <128
如果你真的想避免额外的表格来表达关系,你可以这样做:
CREATE TABLE "user" (
id integer primary key,
name text not null,
bookmarks integer[] not null
);
CREATE TABLE url (
id integer primary key,
time timestamp with time zone not null,
val text not null
);
然后查找特定用户的所有书签(例如
id
66)将涉及执行类似的操作:
SELECT url,time
FROM (SELECT bookmarks FROM "user" WHERE id=66) u
JOIN url ON url.id=ANY(bookmarks)
ORDER BY TIME;
这就是我不喜欢这个模式的原因。首先,添加一个新书签需要重写书签数组,从而重写整个
user
行(因此逐个添加 n 个书签将需要 Θ(n^2)
时间)。其次,不能在数组的元素上使用外键。第三,许多查询的编写将变得更加复杂,例如为了检索所有用户的所有书签,您必须执行类似的操作:
SELECT "user".id,"user".name,url.val,url.time
FROM "user",
LATERAL unnest((SELECT bookmarks)) b
LEFT JOIN url ON b = url.id;
编辑:所以这是我将使用的模式,我认为它最适合关系范式
CREATE TABLE "user" (
id integer primary key,
name text not null
);
CREATE TABLE url (
id integer primary key,
val text not null
);
CREATE TABLE bookmark (
user_id integer not null REFERENCES "user",
url_id integer REFERENCES url,
time timestamp with time zone not null,
UNIQUE (user_id,url_id)
);