1

我的情况:

我有一些二进制数据,它们被分成了很多部分。特殊表FileParts包含fileIdpartNodata

我需要把所有部分一起放到另一张桌子上MyFilesStorage

现在我在两种实现之间进行选择:

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$

在这里我使用临时变量。第二个更快,但我不知道会占用更多内存吗?首先我需要内存来将所有文件加载到 RAM,那么首先呢?postgre 会在此处加载所有内容:mainFileData = mainFileData || r.data

也许还有另一种方法可以做到这一点,因为这两种变体都非常慢?在 oracle 中,我DBMS_LOB.APPEND用于此操作。

4

2 回答 2

3

您的方法看起来正确,请在此处查看 PostgreSQL手册

您还可以定义自己的聚合来为您完成这项工作:

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;

编辑:

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 的输出。

于 2012-04-17T16:09:13.600 回答
3

第一个版本较慢,因为 PostgreSQL 不在存储级别进行就地更新,它为每个 UPDATE 创建一个新版本的行。因此,对于以 10Mb 为增量从 0Mb 到 100MB 的行,真正写入磁盘的不是 10x10Mb 而是: 10Mb+20Mb+30Mb+...+90Mb+100Mb = 550Mb。另一方面,内存消耗将保持低水平,一次分配的内存不超过 10Mb。

第二个版本更快,只有 100Mb 可写入,但需要在内存中分配 100Mb。

The structure of the FileParts table with ordered chunks is generally easier to manage for large contents, why bother to convert it into the monolithic other structure?

于 2012-04-17T19:44:33.717 回答