【実務・中級編】 マテリアライズドビュー – PostgreSQL

「毎回計算させるの、もうやめない?」PostgreSQLのマテリアライズドビュー活用術

現場でバリバリ開発していると、一度は直面するよね。「このクエリ、重すぎて話にならない」っていう壁。

JOINを重ねまくった複雑なレポート用クエリや、数百万行のテーブルをガッツリ集計するSQL。これをダッシュボードを開くたびに走らせていたら、PostgreSQLも悲鳴を上げるし、何よりユーザーのUXが最悪だ。

そんな時、「普通のビュー(View)でいいじゃん」って思うかもしれない。でも、普通のビューは「アクセスされるたびに裏で元のクエリを再実行している」だけ。根本的な解決にはならないんだよね。

そこで今回紹介したいのが「マテリアライズドビュー(Materialized View)」だ。これ、知っておくと現場での立ち回りがガラッと変わるよ。

—

マテリアライズドビューとは?

簡単に言うと、「クエリの結果を物理的なテーブルとしてディスクに保存しておくビュー」のことだ。

普通のビューが「レシピ(クエリ)」を保存しているのに対し、マテリアライズドビューは「調理済み料理(結果データ)」を冷蔵庫に保存しているイメージ。だから、取り出すときは超高速。計算コストを「参照時」から「更新時」にシフトさせる戦略だね。

さっそく作ってみよう

例えば、ECサイトの月間売上レポートを出すクエリがあるとしよう。

CREATE MATERIALIZED VIEW monthly_sales_summary AS
SELECT
date_trunc(‘month’, order_date) AS sales_month,
product_id,
sum(amount) AS total_amount
FROM orders
GROUP BY 1, 2;

これを作るだけで、以降は `SELECT FROM monthly_sales_summary` とするだけで、集計処理をすっ飛ばして結果が返ってくる。これ、初めて使うと感動するよ。

—

注意点:データは「勝手に」新しくならない

ここが一番の落とし穴なんだけど、マテリアライズドビューは作成した時点の「スナップショット」に過ぎない。元の `orders` テーブルに新しい注文が入っても、マテリアライズドビューの中身は古いまま。

そこで登場するのが `REFRESH MATERIALIZED VIEW` コマンドだ。

— 最新データに更新する
REFRESH MATERIALIZED VIEW monthly_sales_summary;

実務的なアドバイス

この更新コマンド、実行中は読み取りロックがかかってしまうことがある。大量のデータだと、更新が終わるまでビューへのアクセスが止まってしまうんだよね。

そんな時はこう書こう。

— CONCURRENTLY を付けると、ロックをかけずにバックグラウンドで更新できる
REFRESH MATERIALIZED VIEW CONCURRENTLY monthly_sales_summary;

※ただし、これを使うにはビューに「一意インデックス(Unique Index)」が貼ってある必要があるから忘れないように。

—

どんな時に使うべき?

万能薬じゃないから、使いどころは見極めよう。

  • 向いているケース:
  • データの参照頻度が非常に高い。
  • クエリの実行コストがめちゃくちゃ高い(数秒〜数十秒かかる)。
  • リアルタイム性がそこまで厳密に求められない(1時間ごとの更新でOK、など)。
  • 向いていないケース:
  • 常に最新のデータが必要なトランザクション処理。
  • データ更新の頻度が凄まじく高く、REFRESHが追いつかない。

最後に:先輩からのアドバイス

実務では、この `REFRESH` をどう回すかが鍵になる。僕なら `pg_cron` を使って深夜にバッチ実行するか、あるいはトリガーを使って更新を制御するかな。

「とりあえずビューを作ればいいや」と安易に考えるんじゃなくて、「これはリアルタイム性が必要か? それとも計算済み結果をキャッシュすべきか?」という視点を持つこと。これができるエンジニアは、DBのパフォーマンスチューニングで絶対に重宝されるよ。

まずは自分のプロジェクトの「重いクエリ」を一つ選んで、試しにマテリアライズドビュー化してみてよ。その爆速っぷりに、きっとニヤリとするはずだから。

また何か詰まったら、いつでも聞いてくれ!

コメント

タイトルとURLをコピーしました