PostgreSQL和PHP:以多种模式存储大型文件:BLOB或BYTEA

PostgreSQL和PHP:以多种模式存储大型文件:BLOB或BYTEA,php,postgresql,pdo,Php,Postgresql,Pdo,我需要在Postgres数据库中存储大文件(从几MB到1GB)。数据库有多个架构。看起来Postgres有两个选项来存储大型对象:LOB和BYTEA。然而,我们似乎遇到了每一个选择的问题 高球。这几乎是理想的,可以存储高达2GB的数据,并允许流式传输,这样我们在读取LOB时不会达到PHP后端的内存限制。但是,所有blob都存储在pg_目录中,并且不是模式的一部分。当您尝试使用带有选项-n和-b的pg_dump来转储一个带有blob的模式时,这会导致一个大问题。它正确地转储模式数据,但是它包含数据

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

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

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

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


    谢谢。

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

    您需要将bytea列的存储模式设置为“external”以禁用压缩,然后您可以在bytea列上使用
    substring
    ,仅获取其中的一部分。至少根据文档,这将DTRT并有效地访问数据库端的值的必要部分:

    因此,创建一个有点像这样的模式:

    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)
    计数中,因此很难验证数据库是否按照文档所述进行操作。

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

    您需要将bytea列的存储模式设置为“external”以禁用压缩,然后您可以在bytea列上使用
    substring
    ,仅获取其中的一部分。至少根据文档,这将DTRT并有效地访问数据库端的值的必要部分:

    因此,创建一个有点像这样的模式:

    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;
    

    不幸的是,
    explain(缓冲区打开)中似乎没有计算TOAST数据的获取
    计数,因此很难验证数据库是否按照文档所述进行操作。

    pg\u catalog.pg\u largeobject实际存储大型对象的系统表本质上是一个按pageno排序的每个对象的字节块列表,这是一个从0到N的顺序块号

    Table "pg_catalog.pg_largeobject" Column | Type | Modifiers --------+---------+----------- loid | oid | not null pageno | integer | not null data | bytea | Indexes: "pg_largeobject_loid_pn_index" UNIQUE, btree (loid, pageno) 表“pg_目录.pg_大对象” 列|类型|修饰符 --------+---------+----------- loid | oid |非空 页码|整数|不为空 数据| bytea | 索引: “pg_largeobject_loid_pn_index”唯一,B树(loid,页码) 这些块的最大大小是2048字节(可以更改,但要以服务器重新编译为代价),这对于几百兆字节的块来说是非常小的


    因此,在您的案例中,一个选项是在您自己的模式中复制一个类似的结构,可能具有更大的块,并通过迭代
    pageno
    列表来实现流式访问。总之,一般来说,列内容越小越好。例如,
    pg\u dump
    在客户端内存需求方面很好地处理单行中的大bytea内容并不明显。

    pg\u catalog.pg\u largeobject系统表(其中实际存储了大对象)本质上是按pageno排序的每个对象bytea块的列表,这是一个从0到N的连续块编号

    Table "pg_catalog.pg_largeobject" Column | Type | Modifiers --------+---------+----------- loid | oid | not null pageno | integer | not null data | bytea | Indexes: "pg_largeobject_loid_pn_index" UNIQUE, btree (loid, pageno) 表“pg_目录.pg_大对象” 列|类型|修饰符 --------+---------+----------- loid | oid |非空 页码|整数|不为空 数据| bytea | 索引: “pg_largeobject_loid_pn_index”唯一,B树(loid,页码) 这些块的最大大小是2048字节(可以更改,但要以服务器重新编译为代价),这对于几百兆字节的块来说是非常小的


    因此,在您的案例中,一个选项是在您自己的模式中复制一个类似的结构,可能具有更大的块,并通过迭代
    pageno
    列表来实现流式访问。总之,一般来说,列内容越小越好。例如就客户端内存需求而言,
    pg_dump
    很好地处理单行中的大型bytea内容,这一点并不明显。

    为什么不只保存文件路径?因为外部文件不是数据库的一部分,当您将部分数据存储在数据库之外时,您会丢失诸如酸保护之类的东西。为什么不呢只保存文件路径?因为外部文件不是数据库的一部分,当你将部分数据存储在数据库之外时,你会丢失一些类似ACID保护的东西。是的,我也注意到了。试试你现在的建议。我会看看它是怎么工作的。是的,我也注意到了。试试你现在的建议。我将看到它的总体工作原理。