表
让我们假设我们有一个文章表:
CREATE TABLE articles
(
id integer PRIMARY KEY,
last_update timestamp NOT NULL,
...
);
用户可以为文章添加书签:
CREATE TABLE bookmarks
(
user integer NOT NULL REFERENCES users(id),
article integer NOT NULL REFERENCES articles(id),
PRIMARY KEY(user, article),
last_seen timestamp NOT NULL
);
要实现的功能
我现在要做的是通知用户在用户最后一次看到它们之后已经更新的文章。通过网络界面访问整个系统。每当请求页面时,系统应检查是否应通知用户有关更新的文章(类似于此处页面顶部的通知栏)。
问题
鉴于上面的两个表都包含数千万行,这种特性的最佳和最有效的实现是什么?
我的解决方案#1
可以像这样进行简单的连接:
SELECT ... FROM articles, bookmarks WHERE bookmarks.user = 1234
AND bookmarks.article = articles.article AND last_seen < last_update;
但是,我担心如果用户有很多书签文章(这可能比您想象的更频繁地发生),那么执行此 JOIN 可能会很昂贵,特别是如果数据库(在我的情况下为 PostgreSQL)必须遍历主键上的索引为articles
每篇添加书签的文章。此外,last_seen < last_update
只能在访问磁盘上的行后检查谓词。
我的解决方案#2
另一种方法更困难,但在我的情况下可能会更好。它涉及通过通知列扩展书签表:
CREATE TABLE bookmarks
(
user integer NOT NULL REFERENCES users(id),
article integer NOT NULL REFERENCES articles(id),
PRIMARY KEY(user, article),
last_seen timestamp NOT NULL,
notify boolean NOT NULL DEFAULT false
);
CREATE INDEX bookmark_article_idx ON bookmarks (article);
每当一篇文章被更新时,更新操作应该为每个收藏了这篇文章的用户触发设置 notify 为 true。想到的最大缺点是,如果一篇文章被添加了很多书签,那么将很多行的 notify 设置为 true 可能会很昂贵。优点可能是检查通知很简单:
SELECT article FROM bookmarks WHERE user = 1234 AND notify = true;
最后的想法
我认为如果页面浏览次数(以及系统检查通知的次数)超过文章更新次数,第二种方法会更有效。但是,情况可能并非总是如此。可能有些用户有很多书签文章,每月只登录一次几分钟,而其他用户几乎每分钟检查一次更新。
还有第三种方法涉及通知表,一旦文章更新,系统就会在其中为每个用户插入通知。但是,我认为方法 #2 的一种低效变体,因为它涉及保存通知。
当两个表都包含数百万行时,哪种方法最有效?你有另一种可能更好的方法吗?