2012-04-17 8 views
1

私の場合:PostgreSQLデータベースのバイナリコンテンツをバイト列に追加します。

私はいくつかのバイナリデータを持っています。特別表FilePartsは、fileId,partNoおよびdataを含む。

すべての部品を別のテーブルにまとめてMyFilesStorageとする必要があります。

今、私は2つの実現の間で選択しています:

DO $CODE$ 
declare 
    r record; 
begin 
    UPDATE public.MyFilesStorage SET mainFileData = E''::bytea WHERE id = 'e14a26c0-db4b-47e1-8b66-e091fb3ba199'::uuid; 

    for r in (select data 
      from public.FileParts 
      where fileId = '89cb8598-436b-49b3-bb1c-34534c6d068e'::uuid 
      order by partNo) loop 
    UPDATE public.MyFilesStorage SET mainFileData = mainFileData || r.data WHERE id = 'e14a26c0-db4b-47e1-8b66-e091fb3ba199'::uuid; 
    end loop; 

end; 
$CODE$ 

私は空のように、データを設定し、その後、部品を一つずつ読み、メインテーブルに各パーツを追加します。

他の変形例:ここでは

DO $CODE$ 
declare 
    r record; 
    p_result bytea; 
begin 
    p_result = E''::bytea; 

    for r in (select data 
      from public.FileParts 
      where fileId = '89cb8598-436b-49b3-bb1c-34534c6d068e'::uuid 
      order by partNo) loop 
    p_result = p_result || r.data; 
    end loop; 

    UPDATE public.MyFilesStorage SET mainFileData = p_result WHERE id = 'e14a26c0-db4b-47e1-8b66-e091fb3ba199'::uuid; 
end; 
$CODE$ 

私は一時変数を使用します。 2番目の方がはるかに速いですが、私はもっと記憶を取ることを知っていませんか?まず、すべてのファイルをRAMにロードするためのメモリが必要ですか?最初はどうですか? postgreはすべてのコンテンツをここにロードしますか:mainFileData = mainFileData || r.data

おそらく、これを行う別の方法があります。両方のバリエーションがあるためveeeeery slow? oracleでは、この操作にはDBMS_LOB.APPENDを使用します。

+2

PostgreSQLラージオブジェクト機能を使用することができます。この場合、最後に検索して書き込みを行うことで高速追加を行うことができます。 http://www.postgresql.org/docs/9.1/interactive/lo-interfaces.html#LO-SEEKバイトアに比べていくつかの制限がありますので、注意深く見てください。一方、ファイルパーツを使って何をしているのかは、PostgreSQLがTOASTシステムを介して内部的に行っていることと非常に似ていますが、デフォルトで圧縮を試みる点が異なります。 http://www.postgresql.org/docs/9.1/interactive/storage-toast.htmlこれは完全に自動で透過的です。 – kgrittn

+0

ありがとう。それは非常に有用なアドバイスです!私はLOインターフェイスを試してみます。 – Yavanosta

答えて

3

PostgreSQLはストレージレベルでのインプレース更新を行わないため、最初のバージョンの方が処理が遅いため、UPDATEごとに新しいバージョンの行が作成されます。 0Mbから100MB増分で10Mb増分になるローの場合、実際にディスクに書き込まれるのは10x10Mbではなく、10Mb + 20Mb + 30Mb + ... + 90Mb + 100Mb = 550Mbです。 一方、メモリ消費量は、メモリに一度に割り当てられる10Mb以上では低く留まります。

第2のバージョンは書き込み速度が100Mbで高速ですが、メモリに100Mbを割り当てる必要があります。

オーダーされたチャンクを持つテーブルの構造は、大規模なコンテンツの管理が一般的に簡単ですが、それをモノリシックな他の構造に変換するのはどうしてですか?

+0

これは大きなシステムの一部です。PostgreSQLに移行しています。だから私はこの動作を変更することはできません。 他のすべてのデータベース(Oracle、SQL Server)には、大規模なバイナリオブジェクトを操作してメインテーブルのデータファイルの外に格納するための特殊なインストゥルメントがあると言わなければなりません。しかしポストグレはそうではなく、非常に残念です。 – Yavanosta

+1

私は同意しません。 PgのBYTEAタイプはOracleのLONG RAWと比較する必要があります。 OracleのBLOB型とそのDBMS_LOBパッケージは、lo_ *関数を使用してPgのラージ・オブジェクト(Oid列を「ロケータ」として)と比較/置換する必要があります。 –

+0

はい、あなたは正しいですが、LargeObjectでSQLをスローする方法はありません。例えば、私はlo_sizeにアクセスできるのはドライバからの呼び出しだけです。私は 'lo_size(111)'を実行できません。 もし私が間違っていたら、それはとても良いでしょう。 – Yavanosta

3

あなたのアプローチは正しいように見えます。PostgreSQL manual hereをチェックしてください。

ます。また、 define your own aggregateあなたのための仕事をすることができます

CREATE AGGREGATE bytea_add(bytea) 
(
    sfunc = byteacat, 
    stype = bytea, 
    initcond = E'' 
); 

そして、このような使用の一般的なSQL、:

UPDATE public.MyFIlesStorage SET mainFileData = (
    SELECT bytea_add(data) FROM public.FileParts 
    WHERE fileId = '89cb8598-436b-49b3-bb1c-34534c6d068e'::uuid 
    -- ORDER BY partNo -- ORDER BY partNo will not work 
) 
WHERE id = 'e14a26c0-db4b-47e1-8b66-e091fb3ba199'::uuid; 

EDIT:

UPDATE public.MyFilesStorage mfs SET mainFileData = fp.all_data 
    FROM (
    SELECT bytea_add(data) OVER (ORDER BY partNo) AS all_data, 
      rank() OVER (ORDER BY partNo DeSC) AS pos 
     FROM public.FileParts 
    WHERE fileId = '89cb8598-436b-49b3-bb1c-34534c6d068e'::uuid 
) AS fp 
WHERE fp.pos = 1 
    AND mfs.id = 'e14a26c0-db4b-47e1-8b66-e091fb3ba199'::uuid; 

内部SQLの出力を個別にチェックすることができます。

+0

お返事ありがとうございました。 Order byが動作しない場合、 'bytea_add'が正しいオーガーの部品を集める方法を保証するにはどうすればいいですか? – Yavanosta

+0

@ Yavanosta、PostgreSQL 8.4より、順序を正確にするために 'bytea_add(data ORDER BY partNo)'を使うことができます。 – vyegorov

関連する問題