PostgreSQL에서 점 진화 된 뷰 새로 고침


33

PostgreSQL에서 구체화 된 뷰를 점진적으로 새로 고칠 수 있습니까? 즉 새로운 데이터 또는 변경된 데이터에 대해서만 가능합니까?

이 테이블 및 구체화 된 뷰를 고려하십시오.

CREATE TABLE graph (
   xaxis integer NOT NULL,
   value integer NOT NULL,
);

CREATE MATERIALIZED VIEW graph_avg AS 
SELECT xaxis, AVG(value)
FROM graph
GROUP BY xaxis

주기적으로 새 값이 추가 graph되거나 기존 값이 업데이트됩니다. graph_avg업데이트 된 값에 대해서만 두 시간마다 보기를 새로 고치고 싶습니다 . 그러나 PostgreSQL 9.3에서는 전체 테이블이 새로 고쳐집니다. 시간이 많이 걸립니다. 다음 버전 9.4는 CONCURRENT업데이트를 허용 하지만 여전히 전체보기를 새로 고칩니다. 1 억 줄의 행으로 몇 분이 걸립니다.

업데이트 된 값과 새로운 값을 추적하고 뷰를 부분적으로 만 새로 고치는 좋은 방법은 무엇입니까?

답변:


22

항상 "구체화 된 뷰"로 제공되는 자체 테이블을 구현할 수 있습니다. 그것은 당신이 MATERIALIZED VIEWPostgres 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변경할 수 있습니다.

테이블에 대한 데이터 수정 CTE가있는 기본 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') 의 타임 스탬프를 테이블에 저장 한 트랜잭션 타임 스탬프로 다시 작성하십시오 . 한 번의 거래로 모든 것 .

  • 참고 부분 인덱스가 커버에 큰 것을 INSERTUPDATE운영 있지만 DELETE. 이를 다루려면 전체 테이블을 고려해야합니다. 그것은 모두 정확한 요구 사항에 달려 있습니다.


구체화 된 견해를 명확하게하고 다른 답변을 제안 해 주셔서 감사합니다.
user4150760

13

동시 업데이트 (Postgres 9.4)

요청한대로 증분 업데이트는 아니지만 Postgres 9.4는 새로운 동시 업데이트 기능을 제공 합니다.

문서를 인용하려면…

PostgreSQL 9.4 이전의 구체화 된 뷰를 새로 고치려면 전체 테이블을 잠그고 쿼리하는 것을 방지해야했으며 새로 고침이 독점 잠금을 획득하는 데 오랜 시간이 걸렸을 때 (만약 사용하여 쿼리가 완료 될 때까지 기다리는 경우) 후속 쿼리를 보류하고 있습니다. 이제 CONCURRENTLY 키워드를 사용하여이를 완화 할 수 있습니다.

 postgres=# REFRESH MATERIALIZED VIEW CONCURRENTLY mv_data;

하지만 구체화 된 뷰에는 고유 한 인덱스가 있어야합니다. 구체화 된 뷰를 잠그는 대신 임시 업데이트 된 버전을 생성하고 두 버전을 비교 한 다음 구체화 된 뷰에 INSERT 및 DELETE를 적용하여 차이를 적용합니다. 이는 쿼리가 업데이트되는 동안 구체화 된 뷰를 계속 사용할 수 있음을 의미합니다. 비 동시 형식과 달리 튜플은 고정되지 않으며 위에서 언급 한 DELETE로 인해 죽은 튜플을 남길 수있는 진공이 필요합니다.

이 동시 업데이트는 여전히 완전한 새 쿼리 (증분 아님)를 수행하고 있습니다. 따라서 CONCURRENTLY는 전체 계산 시간을 절약하지 않고 업데이트 중에 구체화 된 뷰를 사용할 수없는 시간을 최소화합니다.


11
잠시 동안 나는 자세히 읽을 때까지 흥분했다. it instead creates a temporary updated version of it...compares the two versions-이것은 임시 업데이트 된 버전이 여전히 전체 계산이며 기존 뷰에 차이를 적용 함을 의미합니다. 따라서 본질적으로 여전히 모든 계산을 다시 수행하지만 임시 테이블에서만 수행합니다.
user4150760

5
아, 사실, CONCURRENTLY전체 계산 시간을 절약하지 않고 업데이트 중에 구체화 된 뷰를 사용할 수없는 시간을 최소화합니다.
Basil Bourque
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.