

# lo モジュールを使用したラージオブジェクトの管理
<a name="PostgreSQL_large_objects_lo_extension"></a>

lo モジュール（拡張機能）は、JDBC または ODBC ドライバを介して PostgreSQL データベースを操作するデータベースユーザーおよび開発者向けです。JDBC と ODBC はどちらも、ラージオブジェクトの参照が変更されたときに、データベースがラージオブジェクトの削除を処理することを想定しています。ただし、PostgreSQL はそのように動作しません。PostgreSQL では、オブジェクトの参照が変更されたときにオブジェクトを削除する必要があるとは想定していません。その結果、オブジェクトはディスク上に残り、参照されません。lo 拡張機能には、必要に応じてオブジェクトを削除するための参照変更時にトリガーするために使用する関数が含まれています。

**ヒント**  
データベースが lo 拡張機能の恩恵を受けるかどうかを判断するには、`vacuumlo` ユーティリティを使用して、孤立したラージオブジェクトをチェックします。アクションを実行せずに孤立したラージオブジェクトのカウントを取得するには、`-n` オプション (no-op) を使ってユーティリティを実行します。この方法については、下記の「[vacuumlo utility](#vacuumlo-utility)」を参照してください。

Lo モジュールは Aurora PostgreSQL 13.7、12.11、11.16、10.21 以降のマイナーバージョンで利用できます。

モジュール（拡張機能）をインストールするには、`rds_superuser` 権限が必要です。lo 拡張機能をインストールすると、データベースに次のものが追加されます。
+ `lo` — これは、バイナリラージオブジェクト (BLOB) やその他のラージオブジェクトに使用できるラージオブジェクト (lo) データ型です。`lo` データ型は、`oid` データ型のドメインです。つまり、オプションの制約を持つオブジェクト識別子です。詳細については、PostgreSQL ドキュメントの「[オブジェクト識別子](https://www.postgresql.org/docs/14/datatype-oid.html)」を参照してください。簡潔に言うと、`lo` データ型を使用して、ラージオブジェクト参照を保持するデータベース列を他のオブジェクト識別子 (OID) と区別できます。
+ `lo_manage` — これは、ラージオブジェクト参照を含むテーブル列のトリガーで使用できる関数です。ラージオブジェクトを参照する値を削除または変更すると、トリガーによってリファレンスからオブジェクト (`lo_unlink`) のリンクが解除されます。列がラージオブジェクトへの唯一のデータベース参照である場合にのみ、列でトリガーを使用します。

ラージオブジェクトモジュールの詳細については、PostgreSQL ドキュメントの「[lo](https://www.postgresql.org/docs/current/lo.html)」を参照してください。

## lo 拡張機能のインストール
<a name="PostgreSQL_large_objects_lo_extension.install"></a>

lo 拡張機能をインストールする前に、`rds_superuser` 権限があることを確認してください。

**lo 拡張機能をインストールするには**

1. `psql` を使用して、Aurora PostgreSQL DB クラスターのプライマリ DB インスタンスに接続します。

   ```
   psql --host=your-cluster-instance-1.666666666666.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password
   ```

   プロンプトが表示されたら、パスワードを入力します。`psql` クライアントが接続し、プロンプトとしてデフォルトの管理用接続データベースである `postgres=>` を表示します。

1. 次のように 拡張機能をインストールします。

   ```
   postgres=> CREATE EXTENSION lo;
   CREATE EXTENSION
   ```

`lo` データ型を使用して、テーブルの列を定義できるようになりました。例えば、ラスターイメージデータが含まれるテーブルを作成できます (`images`)。次の例に示すように、列 `raster` の `lo` データ型を使って、テーブルを作成できます。

```
postgres=> CREATE TABLE images (image_name text, raster lo);
```

## lo\$1manage トリガー関数を使用してオブジェクトを削除する
<a name="PostgreSQL_large_objects_lo_extension.using"></a>

`lo` または他のラージオブジェクト列の `lo_manage` 関数を使って、`lo` が更新または削除されたときにクリーンアップ（および孤立したオブジェクトを防ぐ）ことができます。

**ラージオブジェクトを参照する列にトリガーを設定するには**
+ 次のいずれかを行います。
  + 引数に列名を使用して、ラージオブジェクトへの一意の参照を含むように、各列に BEFORE UPDATE トリガーまたは BEFORE DELETE トリガーを作成します。

    ```
    postgres=> CREATE TRIGGER t_raster BEFORE UPDATE OR DELETE ON images
        FOR EACH ROW EXECUTE FUNCTION lo_manage(raster);
    ```
  + トリガーは、列が更新されている場合にのみ適用します。

    ```
    postgres=> CREATE TRIGGER t_raster BEFORE UPDATE OF images
        FOR EACH ROW EXECUTE FUNCTION lo_manage(raster);
    ```

`lo_manage` トリガー関数は、トリガーの定義方法に応じて、列データの挿入または削除のコンテキストでのみ機能します。データベースで `DROP` または `TRUNCATE` 式を実行しても効果はありません。つまり、孤立したオブジェクトを作成しないようにするには、削除する前にテーブルからオブジェクト列を削除する必要があります。

例えば、`images` テーブルを含むデータベースを削除するとします。列は、次のように削除します。

```
postgres=> DELETE FROM images COLUMN raster
```

`lo_manage` 関数がその列で削除を処理するために定義されていると仮定すると、テーブルを安全に削除できます。

## `vacuumlo` を使用して孤立したラージオブジェクトを削除する
<a name="PostgreSQL_large_objects_lo_extension.vacuumlo-utility"></a>

 `vacuumlo` ユーティリティは、孤立したラージオブジェクトを識別し、データベースから削除します。このユーティリティは PostgreSQL 9.1.24 以降で使用可能です。データベースユーザーがラージオブジェクトを日常的に操作する場合は、`vacuumlo` をときどき実行して、孤立したラージオブジェクトをクリーンアップすることをお勧めします。

lo 拡張機能をインストールする前に、`vacuumlo` を使用して Aurora PostgreSQL DB クラスターにメリットがあるかどうかを評価できます。これを行うには、`-n` オプション (no-op) を使用して `vacuumlo` を実行し、以下に示すように、削除される内容を表示します。

```
$ vacuumlo -v -n -h your-cluster-instance-1.666666666666.aws-region.rds.amazonaws.com -p 5433 -U postgres docs-lab-spatial-db
Password:*****
Connected to database "docs-lab-spatial-db"
Test run: no large objects will be removed!
Would remove 0 large objects from database "docs-lab-spatial-db".
```

出力が示すように、孤立したラージオブジェクトは、この特定のデータベースでは問題になりません。

このユーティリティの詳細については、PostgreSQL ドキュメントの「[https://www.postgresql.org/docs/current/vacuumlo.html](https://www.postgresql.org/docs/current/vacuumlo.html)」を参照してください。

## `vacuumlo` の仕組みについて
<a name="PostgreSQL_large_objects_lo_extension.vacuumlo-remove"></a>

 `vacuumlo` コマンドは、ユーザーテーブルに影響や矛盾を引き起こすことなく、PostgreSQL データベースから孤立したラージオブジェクト (LO) を削除します。

コマンドの仕組みは次のとおりです。

1. まず、`vacuumlo` は、データベース内のラージオブジェクトのオブジェクト ID (OID) がすべて含まれる一時テーブルを作成します。

1. 次に、`vacuumlo` は、データ型 `oid` または `lo` を使用するデータベース内のすべての列をスキャンします。`vacuumlo` がこれらの列で一致する OID を検出すると、一時テーブルから OID が削除されます。`vacuumlo` は、これらのタイプに基づくドメインではなく、`oid` または `lo` という名前の列のみをチェックします。

1. 一時テーブルの残りのエントリは孤立した LO を表し、`vacuumlo` によってその後安全に削除されます。

## `vacuumlo` パフォーマンスの向上
<a name="PostgreSQL_large_objects_lo_extension.vacuumlo-improve"></a>

 `-l` オプションを使用してバッチサイズを増やすことで、`vacuumlo` のパフォーマンスを向上させることができます。これにより、`vacuumlo` は一度により多くの LO を処理できます。

 システムに十分なメモリがあり、一時テーブルを完全にメモリに格納できる場合は、データベースレベルで `temp_buffers` 設定を大きくするとパフォーマンスが向上する可能性があります。こうするとテーブルがメモリ内に完全に格納されるため、全体的なパフォーマンスの向上を期待できます。

以下は、一時テーブルのサイズを見積もるクエリです。

```
SELECT
    pg_size_pretty(SUM(pg_column_size(oid))) estimated_lo_temp_table_size
FROM
    pg_largeobject_metadata;
```

## ラージオブジェクトに関する考慮事項
<a name="PostgreSQL_large_objects_lo_extension.vacuumlo-consider"></a>

ラージオブジェクトを操作するときに注意すべき重要な考慮事項を以下に示します。
+ 現在、孤立した LO を削除する方法はほかにないため、`Vacuumlo` が唯一の解決策です。
+ レプリケーションテクノロジーを使用する pglogical、ネイティブ論理レプリケーション、AWS DMS などのツールは、ラージオブジェクトのレプリケーションをサポートしていません。
+ データベーススキーマを設計するときは、可能な限りラージオブジェクトは使用せず、代わりに `bytea` などの代替データ型を使用することを検討してください。
+ 孤立した LO の問題を防ぐために、少なくとも毎週定期的に `vacuumlo` を実行します。
+ 孤立した LO が作成されないように、ラージオブジェクトを保存するテーブルで `lo_manage` 関数のトリガーを使用します。