您始终可以实现自己的表作为“物化视图”。这是您MATERIALIZED VIEW
在Postgres 9.3中以任何一种方式实现之前必须要做的。
例如,您可以创建一个普通的VIEW
:
CREATE VIEW graph_avg_view AS
SELECT xaxis, AVG(value) AS avg_val
FROM graph
GROUP BY xaxis;
并在一次或每次需要重新开始时将结果整体化:
CREATE TABLE graph_avg AS
SELECT * FROM graph_avg_view
(或者使用SELECT
直接的语句,而无需创建一个VIEW
。)
然后,根据你的使用情况未披露的细节,你可以DELETE
/ UPDATE
/ INSERT
手动更改。
一个基本的DML语句,其中包含用于表的数据修改CTE,如下所示:
假设没有其他人试图写入到graph_avg
并行(阅读是没有问题的):
WITH del AS (
DELETE FROM graph_avg t
WHERE NOT EXISTS (SELECT 1 FROM graph_avg_view v WHERE v.xaxis = v.xaxis);
)
, upd AS (
UPDATE graph_avg t
FROM graph_avg_view v
WHERE t.xaxis = v.xaxis
AND t.avg_val <> v.avg_val
)
INSERT INTO graph_avg t
SELECT *
FROM graph_avg_view v
LEFT JOIN graph_avg t USING (xaxis)
WHERE t.xaxis IS NULL;
但这很可能应该进行优化。
基本配方:
- 将
timestamp
默认列添加now()
到基表中。叫它ts
。
- 如果您有更新,请添加触发器以设置每次更改
xaxis
或都会更改的当前时间戳value
。
创建一个小表以记住最新快照的时间戳。让我们称之为mv
:
CREATE TABLE mv (
tbl text PRIMARY KEY
, ts timestamp NOT NULL DEFAULT '-infinity'
); -- possibly more details
创建此部分多列索引:
CREATE INDEX graph_mv_latest ON graph (xaxis, value)
WHERE ts >= '-infinity';
使用最后一个快照的时间戳作为查询中的谓词,以完美使用索引来刷新快照。
在事务结束时,删除索引并用事务时间戳替换索引谓词中的时间戳(最初是'-infinity'
)来重新创建索引,该谓词 也要保存到表中。一切都在一次交易中。
请注意,部分索引可以很好地覆盖INSERT
和UPDATE
操作,但不是DELETE
。为此,您需要考虑整个表格。这完全取决于确切的要求。