2

我需要在 Postgres 数据库中存储大文件(从几 MB 到 1GB)。数据库有多个模式。看起来 Postgres 有 2 个选项来存储大对象:LOB 和 BYTEA。然而,我们似乎遇到了每个选项的问题。

  1. 高球。这几乎是理想的,最多可以存储 2GB 并允许流式传输,这样我们在读取 LOB 时就不会达到 PHP 后端的内存限制。但是,所有 blob 都存储在 pg_catalog 中,并且不是架构的一部分。当您尝试使用带有选项 -n 和 -b 的 pg_dump 来仅转储一个带有其 blob 的模式时,这会导致一个大问题。它会正确转储模式数据,然后它包括数据库中的所有 blob,而不仅仅是属于特定模式的 blob。有没有办法使用 pg_dump 或其他一些实用程序来转储单个模式及其 blob?

  2. 白茶。这些是按模式正确存储的,因此 pg_dump –n 可以正常工作,但是我似乎找不到流式传输数据的方法。这意味着如果数据大于内存限制,则无法从 PHP 访问数据。

有没有其他方法可以在 Postgres 中存储大数据,允许流式传输并正确使用每个数据库的多个模式?

谢谢。

4

2 回答 2

3

虽然使用 bytea 不支持流式/文件式 API,但您可以使用它仅获取部分内容,因此它支持“分块”。

您需要将 bytea 列的存储模式设置为“外部”以禁用压缩,然后您可以substring在 bytea 列上使用它来仅获取其中的一部分。至少根据文档,这将 DTRT 并仅有效地访问数据库端值的必要部分: http ://www.postgresql.org/docs/current/static/storage-toast.html

所以创建一个有点像这样的模式:

create table media.entity(entity_id serial primary key, content bytea not null);
alter table media.entity alter column content set storage external;

然后从内容中获取 8Kb:

select substring(content, 1, 8192) from media.entity where entity_id = 1;
select substring(content, 8193, 8192) from media.entity where entity_id = 1;

不幸的是,TOAST 数据的获取似乎没有计入explain (buffers on)计数,因此很难验证数据库是否按照文档所述进行。

于 2012-10-10T10:53:44.553 回答
1

实际存储大对象的pg_catalog.pg_largeobject系统表本质上是按pageno排序的每个对象 bytea 块的列表,它是从 0 到 N 的顺序块编号。

表“pg_catalog.pg_largeobject”
 专栏 | 类型 | 修饰符
--------+----------+------------
 类人 | 类 | 不为空
 页面 | 整数 | 不为空
 数据 | 字节茶 |
索引:
    “pg_largeobject_loid_pn_index”唯一,btree(loid,pageno)

这些块的最大大小为 2048 字节(可以更改,但要以服务器重新编译为代价),这对于数百兆字节的 blob 来说非常小。

因此,在您的情况下,一种选择是在您自己的模式中复制类似的结构,可能具有更大的块,并通过遍历pageno. 无论如何,通常具有较小的列内容会更好。例如,就pg_dump客户端内存要求而言,在单行中很好地处理大字节茶内容并不明显。

于 2012-10-10T13:48:46.717 回答