PostgreSQLは広く使われている素晴らしいBLOBインターフェイスを提供しています。 しかし、最近、さまざまな顧客が直面している問題に遭遇しましたが、PostgreSQLがBlob、特にBLOBのクリーンアップをどのように処理するかを少し反映して理解する
PostgreSQL BLOBインターフェイスの使用
PostgreSQLでは、バイナリデータを格納するためにさまざまな手段を使用できます。 最も簡単な形式は、間違いなく”bytea”(=バイト配列)データ型を使用することです。 この場合、バイナリフィールドは基本的に行の一部と見なされます。ご覧のとおり、これは通常の列であり、通常の列と同じように使用できます。 言及する価値のある唯一のものは、SQLレベルで使用する必要があるエンコーディングです。 PostgreSQLは変数を使用してこの動作を設定します:
test=# SHOW bytea_output;bytea_output--------------hex(1 row)
bytea_output変数は2つの値を受け入れます。”hex”はPostgreSQLに16進形式でデータを送信するように指示します。 「エスケープ」とは、データを8進数の文字列として入力する必要があることを意味します。 フィールドごとに1GBの最大サイズを除いて、ここではアプリケーションが心配する必要はあまりありません。
しかし、PostgreSQLにはバイナリデータを処理するための第二のインターフェイス、BLOBインターフェイスがあります。 私はアクションでこの強力なツールの例を示してみましょう:
test=# SELECT lo_import('/etc/hosts');lo_import-----------80343(1 row)
この場合、/etc/hostsの内容がデータベースにインポートされています。 PostgreSQLにはデータのコピーがあることに注意してください–ファイルシステムへのリンクではありません。 ここで注目すべきことは、データベースが新しいエントリのOID(オブジェクトID)を返すことです。 これらのOidを追跡するために、一部の開発者は次のことを行います:
INSERT 0 1
これは、以下のようなことをしない限り、絶対に問題ありません:
test=# DELETE FROM t_file WHERE id = 1;DELETE 1
問題は、オブジェクトidが忘れられていることです。 しかし、オブジェクトはまだそこにあります。 pg_largeobjectは、PostgreSQL内のバイナリデータの格納を担当するシステムテーブルです。 すべてのlo_functionsは、これらのことを処理するために、単にこのシステムテーブルと通信します。
なぜそれが問題ですか? その理由は簡単です:あなたのデータベースは成長し、”死んだオブジェクト”の数は蓄積されます。 したがって、BLOBエントリを強制終了する正しい方法は次のとおりです:
オブジェクトのリンクを解除することを忘れた場合、長期的には苦しむでしょう–そして、私たちはしばしばそれが起こるのを見てきました。 BLOBインターフェイスを使用している場合は、大きな問題です。
vacuumlo:死んだ大きなオブジェクトのクリーンアップ
しかし、何千、あるいは何百万もの死んだBlobを蓄積したら、どうすれば問題を解決できますか? 答えは”vacuumlo”と呼ばれるコマンドラインツールです。
まずデッドエントリを作成しましょう:
test=# SELECT lo_import('/etc/hosts');lo_import-----------80351(1 row)
次に、任意のクライアントからvacuumloを実行できます:
ご覧のように、2つのデッドオブジェクトがツールによって強制終了されました。 vacuumloは、孤立したオブジェクトをきれいにする最も簡単な方法です。
追加機能
しかし、lo_importとlo_unlinkだけではありません。 PostgreSQLには、ラージオブジェクトを適切に処理するためのさまざまな関数があります。
歴史的な理由から命名規則に従わない2つの関数があります:loreadとlowrite:
pg_catalog | loread | bytea | integer, integer | funcpg_catalog | lowrite | integer | integer, bytea | func
これらは、名前を簡単に変更することができない関数です。 しかし、それらが存在することは注目に値する。
最後に…
PostgreSQL BLOBインターフェイスは本当に便利で、多くのことに使用できます。 美しさは、それが完全にトランザクション的であるため、バイナリコンテンツとメタデータが同期しなくなることができないということです。PostgreSQLで制約を適用するためのトリガーについて詳しく知りたい場合は、Laurenz Albe氏が書いたブログ記事をご覧になることをお勧めします。 それはこの重要なトピックのライトを取除く。