如何在Postgres中创建存储函数更新行?

时间:2011-07-10 15:14:36

标签: sql postgresql

我已经将Postgres与我的Django项目使用了一段时间,但我从来不需要使用存储的函数。对于以下问题找到最有效的解决方案非常重要:

我有一个表,其中包含以下列: 号码| last_update | growth_per_second

我需要一个有效的解决方案来根据last_update和增长因子更新数字,并将last_update值设置为当前时间。我可能有100行,也许150k行。如果可能的话,我需要在同一时间更新所有行,但如果需要太长时间,我可以将它分成较小的部分。

2 个答案:

答案 0 :(得分:1)

  

存储您无法计算的内容   快。

您确定需要维护此信息吗?如果是这样,如果查询速度慢,可以缓存吗?你试图在数据库中保持这些信息的一致性,从而为大规模的桌面冲击做好准备。

答案 1 :(得分:1)

首先,如果你想走这条路,先从服务器编程的PostgreSQL文档开始,然后根据你的尝试回过头来回答一个问题。无论如何,你会想要熟悉这个区域,因为取决于你在做什么......

现在,假设您的数据全部是插入而没有更新,我将直接将此信息存储在您的数据库中。如果它是一个少量的信息,你最终会得到索引扫描,如果你要返回一个小的结果集,你应该能够快速计算。

相反,我会这样做:让你的last_update列成为同一个表的外键。假设你的表看起来像这样:

CREATE TABLE hits (
    id bigserial primary key,
    number_hits bigint not null,
    last_update_id bigint references hits(id),
    ....
);

然后我会创建以下功能。请注意下面的警告。

CREATE FUNCTION last_update(hits) RETURNS hits IMMUTABLE LANGUAGE SQL AS $$
    SELECT * FROM hits WHERE id = $1.last_update_id;
$$;

此功能允许您在较小的结果集上遍历上一个更新记录。请注意,如果您要保证hits表上没有更新或删除,则此处的不可变指定是安全的。如果你这样做,那么你应该将它改为稳定,你就失去了索引输出的能力。如果你做了这个保证然后必须做更新,那么你必须重建任何使用它的索引(reindex表命中),这可能需要一段时间....

从那里,我们可以:

CREATE FUNCTION growth(hits) RETURNS numeric immutable language sql as $$
     SELECT CASE WHEN ($1.last_update).number_hits = 0 THEN NULL 
                 ELSE $1.number_hits / ($1.last_update).number_hits
             END;
 $$;

然后我们可以:

SELECT h.growth -- or alternatively growth(h)
  FROM hits
 WHERE id = 12345;

它会自动计算出来。如果我们想要搜索增长,我们可以索引输出:

CREATE INDEX hits_growth_idx ON hits (growth(hits));

这将预先计算用于搜索目的。这样,如果你想做一个:

SELECT * FROM hits WHERE growth = 1;

它可以对预定义值使用索引扫描。

当然,您可以使用相同的技术进行预先计算和存储,但这种方法更灵活,如果您必须使用大型结果集,您可以始终自行加入一次,并以此方式计算,绕过您的函数