sungyup's.

PostgreSQL / CTE & Views / 5.3 Optimizing Queries with Materialized Views

5.3Optimizing Queries with Materialized Views

자주 사용되고 비싼 쿼리지만 업데이트 주기가 길 때 쓰는 Materialized View

Materialized View

지난번 포스팅에서 살펴본 VIEW는, 참조될 시 실행되는 쿼리다.

이번에 살펴볼 Materialized View는 특정 시점에서만 실행되는 쿼리로, 해당 쿼리 결과는 저장되어 다시 쿼리를 실행하지 않아도 참조될 수 있다.

Creating Materialized View

매 주별 posts와 comments가 받은 좋아요 숫자를 표시하는 쿼리를 작성해보자.

테이블은 posts(id, created_at), likes(post_id, comment_id), comments(id, created_at)가 있다.

우선 데이터 전체를 선택한 후, 필요한 것만으로 좁혀보자.

sql
SELECT * FROM likes LEFT JOIN posts ON posts.id = likes.post_id LEFT JOIN comments ON comments.id = likes.comment_id;

참고로, LEFT JOIN을 안 했으면 아래의 조건들에서 null이 필연적으로 잡히므로 빈 테이블을 반환한다.

sql
SELECT date_trunc('week', COALESCE(posts.created_at, comments.created_at)) AS week, COUNT(posts.id) AS num_likes_for_posts, COUNT(comments.id) AS num_likes_for_comments FROM likes LEFT JOIN posts ON posts.id = likes.post_id LEFT JOIN comments ON comments.id = likes.comment_id GROUP BY week ORDER BY week;

이렇게 쿼리를 작성하면 실행시 약간의 시간이 걸린다. 이 때 Materialized View를 생성하면 쿼리 결과가 저장되어 금방 결과를 얻을 수 있다.

sql
CREATE MATERIALIZED VIEW weekly_likes AS ( SELECT date_trunc('week', COALESCE(posts.created_at, comments.created_at)) AS week, COUNT(posts.id) AS num_likes_for_posts, COUNT(comments.id) AS num_likes_for_comments FROM likes LEFT JOIN posts ON posts.id = likes.post_id LEFT JOIN comments ON comments.id = likes.comment_id GROUP BY week ORDER BY week ) WITH DATA;

조회하고 싶을 땐 아래와 같이 조회한다. 성능이 훨씬 개선된 것을 볼 수 있다.

sql
SELECT * FROM weekly_likes;

Refreshing Materialized Views

하지만, 이렇게 Materialized View를 저장하면, postscomments 테이블이 업데이트되었을 때 캐싱된 데이터가 자동으로 업데이트 되진 않는다.

데이터가 바뀌면 아래와 같이 REFRESH MATERIALIZED VIEW 뷰명 키워드로 업데이트해야 한다.

sql
REFRESH MATERIALIZED VIEW weekly_likes;

따라서, Materialized View는 가끔씩만 업데이트 하는 경우(위의 예시처럼, 한주에 한번 정도라던가)가 필요할 때 사용한다. 자주 사용되고 비싼 쿼리지만, 업데이트 자체는 가끔만 되는 경우가 최적이다.