我的情况:
我有一些二进制数据,已经分解成很多部分。特殊表FileParts
包含fileId
,partNo
和data
。
我需要将所有部分放在另一个表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
?
也许还有另一种方法可以做到这一点,因为两种变体都是 veeeeery slow ?在oracle中,我使用DBMS_LOB.APPEND
进行此操作。
答案 0 :(得分: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;
修改强>
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的输出。
答案 1 :(得分:3)
第一个版本较慢,因为PostgreSQL不在存储级别进行就地更新,它会为每个UPDATE创建一个新版本的行。 因此,对于从0Mb到100MB,增量为10Mb的行,实际写入磁盘的行不是10x10Mb,而是:10Mb + 20Mb + 30Mb + ... + 90Mb + 100Mb = 550Mb 。 另一方面,内存消耗将保持较低,一次在内存中分配不超过10Mb。
第二个版本更快,只能写入100Mb,但需要在内存中分配100Mb。
具有有序块的FileParts
表的结构通常更容易管理大内容,为什么还要将其转换为单片其他结构呢?