バイナリデータをbytea
フィールドにストリーミングしようとしています。プロセスは非常に簡単です:
_loop until the end of the incoming stream
UPDATE myTable SET data = data || $chunk WHERE id = myId
_
$chunk
_は、現在のストリームチャンクのバインディングです。myId
)はすでにNULLデータで存在しますチャンクが格納されるにつれて、データの連結がますます遅くなることを想定して、すべてが適切に機能しています。
SQLの移植性を維持する必要があるため、「PostgreSQLラージオブジェクト」を使用できません。
このプロセスを最適化することは可能ですか?
overlay()
を使用して各チャンクを配置しますか?Postgresのように マルチバージョンモデル の行を更新するということは、新しいコンテンツでその行の2番目のコピーを作成することを意味します。物理的には、インプレース更新はありません。UPDATEは、新しいコンテンツのDELETE + INSERTに似ています。
したがって、上記のループでは、最初のチャンクは1回ではなくN回書き込まれ、2番目のチャンクはN-1回書き込まれ、3回目はN-2回繰り返されます。
さらに悪いことに、これらの書き込みはすべて、ジャーナリングのためにWALファイルに送信する必要があり、行のすべての中間バージョンを自動バキュームプロセスでピックアップして、最終的に破棄する必要があります。
これらのチャンクをクライアントでアセンブルできず、ストリーミングする必要があると仮定すると、次のようなことを行うと役立つ場合があります。
CREATE TEMPORARY sequence s;
CREATE TEMPORARY TABLE buffer(seq int default nextval('s'), chunk bytea);
-- buffer in temporary storage
LOOP
INSERT INTO buffer(chunk) VALUES ($chunk)
END LOOP
-- assemble in final storage
INSERT INTO permanent_table(data)
SELECT string_agg(chunk,''::bytea order by seq) FROM buffer;
TRUNCATE (or DROP) TABLE buffer;
一時テーブルはWALログに記録されないため、少なくともチャンクは2回だけ(バッファーストレージに1回、最終の永続ストレージに1回)、ジャーナルに1回だけ書き込まれます。