Вы всегда можете реализовать свою собственную таблицу, выступающую в качестве «материализованного представления». Это то, что вы должны были сделать до того, как 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 с КТРОМ данных изменений для вашей таблицы , как является :
Предполагая , что никто другой не пытается писать в 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
. Чтобы покрыть это, вам нужно рассмотреть всю таблицу. Все зависит от точных требований.