イントロ
PostgreSQLを使用すると、開発者は、大きなバイナリデータ用に2つの可能なストレージ機能(ByteaとLargeObjects)から選択することができます。
ラージオブジェクトは長い間存在しており、PostgreSQLにはラージバイナリデータを保存するスマートな方法があります。これは、LOBLKSIZE(BLCKSZの4番目)のチャンクに分割することによって行われます。そうすれば、pg_largeobjectのタプルがトーストテーブルにこぼれることはありません。
一方、ビテア バイナリデータをタプルに直接格納するため、スキーマの外観によってはパフォーマンスが低下する可能性があります。
これは、これらのバイナリファイルの操作を処理するためのインテリジェントなインターフェイスがある場合、特に更新によってバイナリファイル全体のごく一部が変更される場合に最適です。
ただし、通常、これを利用するコードをわざわざ作成するのではなく、バイナリデータ全体を再度作成します。
人々に大きなオブジェクトを採用させると私が信じていることの1つは、データベースサーバーからそのファイルシステムにファイルを直接インポートおよびエクスポートするために使用できる機能です。これには欠点があります。アプリケーションが別のサーバー上にある場合は、ファイルを必要な場所に移動するために、より多くのコードが必要になります。
直面する可能性のある問題
過去数日間、JavaCASシステムからのユーザーセッションの情報を格納するために使用されるデータベースを調べる必要がありました。データベースには、それほど大きなオブジェクトではなく、ほぼ1億個の大きなオブジェクトがあることがわかりました。
oidが含まれるフィールドを確認するユーザーテーブルを確認しました フィールドに移動し、それらのフィールドの値を pg_largeobject_metadataと相互参照します。 テーブル。それらの大きなオブジェクトの96%が孤立したオブジェクトであることがわかりました。これらは、ユーザーテーブルのタプルによって参照されなかった大きなオブジェクトです。
さらなる調査の結果、Hibernateは、oidフィールドを持つタプルを削除または更新するときに作成したラージオブジェクトのパージを処理しなかったと結論付けました。そのため、大量の膨張が発生し、掃除機で掃除することはできませんでしたが、pg_largeobjectsテーブルから手動で削除する必要がありました。
CASデータベースの特定のケースでは、このクエリはまだ使用されているラージオブジェクトを識別するのに役立ちました:
SELECT unnest(array[expiration_policy, authentication, services_granted_access_to]) FROM public.ticketgrantingticket UNION SELECT unnest(array[expiration_policy, service]) FROM public.serviceticket
クエリを使用して、削除するオブジェクトを大きなオブジェクトのリストから除外できます。このようなもの:
SELECT lo_unlink(pg_largeobject_metadata.oid) FROM pg_largeobject_metadata WHERE pg_largeobject_metadata.oid NOT IN ( SELECT unnest(array[expiration_policy, authentication, services_granted_access_to]) FROM public.ticketgrantingticket UNION SELECT unnest(array[expiration_policy, service]) FROM public.serviceticket )
結論
ラージオブジェクトには、他のタイプのデータと同じように問題があります(特に、タイプを使用してラージバイナリデータを格納する場合)。長所を活用して短所を軽減するのは、開発者とデータベース管理者の責任です。
クリーンアップを実行するための可能なクエリを提供しましたが、孤立したラージオブジェクトをトリガーでクリーンアップする優れた拡張機能もあります:ラージオブジェクトマネージャー
UPDATE ごとにトリガーを実行するのではなく、静かな時間帯にパージクエリを実行することを好む人もいます。 および削除 。 UPDATEが非常に低いシステムの場合 および/または削除 レート、 oidを持つ各テーブルのトリガー フィールドは、よりエレガントなソリューションのようです。また、トリガー機能を実行しなければならないことによるパフォーマンスの低下は不要です。
いずれにせよ、大きなオブジェクトには依然として大きなファンがいます。これはおそらく、バイナリデータをローカルファイルシステムに直接インポートおよびエクスポートするために提供されている内部関数が原因です。 byteaを使用すると、通常、アプリケーション層でより多くのメモリを使用します。バイナリフィールドを変数に完全に読み込んでから処理するのは、非常に一般的な手順です。
将来のブログ投稿で、過去の開発の1つで使用したbyteaの使用について何か書くかもしれません。