PostgreSQL中的计数器缓存列

she*_*run 11 postgresql performance caching

在我的数据库中我有taskscomments表.每个任务都有很多评论.

我想创建tasks.comments_count一个可以由PostgreSQL自动更新的列,这样我就可以comments_count在选择所有任务时在O(1)时间内获取(并按其排序/过滤).

我知道有一些特定于语言的解决方案,比如ActiveRecord的计数器缓存,但我不想使用它们(我觉得它们很脆弱).我希望PostgreSQL能够处理这样的计数器缓存.

我也知道PostgreSQL支持触发器,但它们很难编写和使用(不是一个可靠的解决方案)

理想情况下,它将是PostgreSQL扩展或我不知道的一些本机功能.

懒惰计算这样的计数器将是一个很大的好处.

Nic*_*nes 18

如果你希望Postgres在插入/更新/删除的基础上自动执行某些操作 - 即如果你希望此操作触发其他操作 - 那么你需要编写一个触发器.

这很简单.很简单,我怀疑有人会打扰创建一个扩展(更不用说语言功能)来节省你的麻烦.而且,无论ActiveRecord在幕后发生什么,它肯定更简单(正如你所指出的那样,更安全).

这样的事情通常都需要(我没有测试过,所以你可能想要这样做......):

CREATE FUNCTION maintain_comment_count_trg() RETURNS TRIGGER AS
$$
BEGIN
  IF TG_OP IN ('UPDATE', 'DELETE') THEN
    UPDATE tasks SET comment_count = comment_count - 1 WHERE id = old.task_id;
  END IF;
  IF TG_OP IN ('INSERT', 'UPDATE') THEN
    UPDATE tasks SET comment_count = comment_count + 1 WHERE id = new.task_id;
  END IF;
  RETURN NULL;
END
$$
LANGUAGE plpgsql;

CREATE TRIGGER maintain_comment_count
AFTER INSERT OR UPDATE OF task_id OR DELETE ON comments
FOR EACH ROW
EXECUTE PROCEDURE maintain_comment_count_trg();
Run Code Online (Sandbox Code Playgroud)

如果你希望它不透气,你需要额外的触发TRUNCATES上comments; 是否值得麻烦取决于你.

要处理tasks.id正在引用的值的更新(通过延迟约束或ON UPDATE操作),那么还有更多内容,但这是一种不常见的情况.

如果您的客户端库/ ORM足够天真地发送每个UPDATE语句中的每个字段,您可能需要一个单独的UPDATE触发器,仅在值实际更改时触发:

CREATE TRIGGER maintain_comment_count_update
AFTER UPDATE OF task_id ON comments
FOR EACH ROW
WHEN (old.task_id IS DISTINCT FROM new.task_id)
EXECUTE PROCEDURE maintain_comment_count_trg();
Run Code Online (Sandbox Code Playgroud)