はじめに
エンジニアとして入社してから 1 ヶ月経った頃,プロダクトで扱っているユーザの不必要になったデータの総削除機能の開発タスクをやらせてもらいました.
このタスクで,データが入っている PostgreSQL のテーブルに対して DELETE することで順調に進んでいましたが,Materialized View では同じ操作でうまくいきませんでした.
この記事では,Materialized View にあるデータをどうすれば削除できるのかを紹介します.
Materialized View でデータを DELETE 句で削除してみる
今回のタスクでは,ユーザに紐づく user_id
のようなカラムを持っているテーブル・Materialized View を対象に削除機能開発を行いました.
テーブルに対して DELETE 句で削除する
まず,user_id
のカラムを持つテーブルを以下で探します.
SELECT table_name
FROM information_schema.columns
WHERE column_name = 'user_id';
table_name
----------
table1
table2
...
上記の結果を利用して,以下のようにテーブル内のデータを削除します.
DELETE FROM table1;
これは問題なく削除されます.
Materialized View に対して DELETE 句で削除する
同じく,user_id
のカラムを持つ Materialized View を以下で探します.
SELECT c.relname AS table_name
FROM pg_class c INNER JOIN pg_attribute a ON c.oid = a.attrelid
WHERE c.relkind = 'm' AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = 'user_id';
table_name
----------
matview1
matview2
...
上記の結果を利用して,テーブルと同じようにデータを削除してみます.
DELETE FROM matview1;
すると,エラーが返ってきてしまいます.
ERROR: cannot change materialized view "matview1"
Materialized View は置換する必要がある
改めて Materialized View とは,PostgreSQL 16 のドキュメントによると,ビューと同じルールシステムを用いているが結果をテーブルの形で保持しているもの,です.
Materialized views in PostgreSQL use the rule system like views do, but persist the results in a table-like form.
テーブルと違い,Materialized Views は作成後に直接 update することができません.これが理由で直接 DELETE
ができませんでした.
The main differences between [materialized views] and [tables] are that the materialized view cannot subsequently be directly updated.
このため,以下のクエリで Materialized View の内容を置換する必要があります.1
REFRESH MATERIALIZED VIEW matview1;
補足:PostgreSQL での置換は完全リフレッシュされる
REFRESH MATERIALIZED VIEW
コマンドの動作としては,PostgreSQL 16 のドキュメントから,Materialized View の内容を「完全」に置き換える,と書かれてあります.
REFRESH MATERIALIZED VIEW completely replaces the contents of a materialized view.
完全リフレッシュの欠点としては,少数のデータを更新する際においても,全データの置換が実行されるため,処理時間が多くかかってしまいます.
この問題に対応するため,PostgreSQL 13 から拡張機能として pg_ivm
が利用できます.IVM (Incremental View Maintenance) と呼ばれる手法で,増分変更のみを計算して置換します.
Incremental View Maintenance (IVM) is a way to make materialized views up-to-date in which only incremental changes are computed and applied on views rather than recomputing the contents from scratch.
おまけ: 特定のカラム名を持つテーブルを探す際に用いた情報について
指定のカラムが含まれるテーブル・Materialized View を取得する際に,information_schema
,pg_class
,pg_attribute
を参照していました.これらの情報は今回の開発環境特有のものではなく,PostgreSQL が提供するものです.
information_schema
について
information_schema
は,データベースに定義されているオブジェクトに関する情報を保持している複数のビューで構成されているものです.
The information schema consists of a set of views that contain information about the objects defined in the current database.
また,このスキーマは標準 SQL に準拠しているため,PostgreSQL 固有の機能に関する情報は含まれません.
pg_
で始まる情報について
PostgreSQL は多くの RDMS のように,スキーマメタデータや内部的な情報を格納している system catalogs
,system views
を持っています.どちらも pg_
で始まる名前のテーブル・ビューになっています.
The system catalogs are the place where a relational database management system stores schema metadata, such as information about tables and columns, and internal bookkeeping information.
今回利用した,pg_class
はテーブルを含むカラムを持っているオブジェクトについての情報を,pg_attribute
はテーブルカラムについての情報を格納しているものです.指定カラムが含まれる Materialized View はこれらの情報を利用して取得していました.
まとめ
Materialized View のデータを削除(置換)する方法を紹介しました.REFRESH MATERIALIZED VIEW
で更新できるのを忘れずに!
-
日本語版 PostgreSQL 16 ドキュメントより,
REFRESH
コマンド操作を「置換」と表現しています. ↩