PostgreSQL和PHP:以多种模式存储大型文件:BLOB或BYTEA
我需要在Postgres数据库中存储大文件(从几MB到1GB)。数据库有多个架构。看起来Postgres有两个选项来存储大型对象:LOB和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的模式时,这会导致一个大问题。它正确地转储模式数据,但是它包含数据
谢谢。尽管使用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保护的东西。是的,我也注意到了。试试你现在的建议。我会看看它是怎么工作的。是的,我也注意到了。试试你现在的建议。我将看到它的总体工作原理。