PostgreSQL中的大对象

我们知道在 Oracle 数据库中,大对象有三种类型,分别是 CLOB,BLOB 和 BFILE。在 Oracle 数据库中大对象最大存储根据配置可以达到 8TB 到 128TB。然而在 PostgreSQL 数据库中并没有提供这三种数据类型。因此在进行迁移的时候,我们需要做类型的映射。我们可以将 CLOB 和 BLOB 分别映射到 text 和 bytea 数据类型上。此外,PostgreSQL 的插件 pg_largeobject 也提供了一种大对象的支持。

text & bytea

CLOB 和 BLOB 分别用于存储字符大对象和二进制大对象,这与 PostgreSQL 中的 text 和 bytea 很类似,因此在迁移 Oracle 数据库的时候也就将他们分别对应起来。

pg_largeobject

pg_largeobject 是 PostgreSQL 插件提供的一个大对象解决方案。在 pg_largeobject 中,所有的大对象都存储在系统表 pg_largeobject 中;此外,每个大对象在系统表 pg_largeobject_metadata 中也会有一条记录大对象的相关元信息,他们的定义如下所示:

sql 复制代码
postgres=# \d pg_largeobject
Table "pg_catalog.pg_largeobject"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
loid | oid | | not null |
pageno | integer | | not null |
data | bytea | | not null |
Indexes:
"pg_largeobject_loid_pn_index" UNIQUE, btree (loid, pageno)
sql 复制代码
postgres=# \d pg_largeobject_metadata
Table "pg_catalog.pg_largeobject_metadata"
Column | Type | Collation | Nullable | Default
----------+-----------+-----------+----------+---------
oid | oid | | not null |
lomowner | oid | | not null |
lomacl | aclitem[] | | |
Indexes:
 "pg_largeobject_metadata_oid_index" UNIQUE, btree (oid)

采用 pg_largeobject 所存储的大对象最大可以达到 4TB 的存储空间,并且支持随机读写。pg_largeobject 采用 OID 的方式来引用 pg_largeobject 表中的大对象。例如,我们创建一个表来存储图片数据,如下所示:

sql 复制代码
CREATE TABLE image(name text, raster oid);

pg_largeobject 提供了一系列函数用于创建、导入和导出大对象,见官方文档服务端函数。下面是简单的大对象插入导出的测试输出:

sql 复制代码
postgres=# INSERT INTO image VALUES('image1', lo_import('/tmp/screenshot.png'));
INSERT 0 1
postgres=# SELECT loid, COUNT(page no) FROM pg_largeobject GROUP BY loid;
 loid  | count
-------+-------
 24598 |    25
(1 row)
   
postgres=# SELECT raster, lo_export(raster, '/tmp/screenshot-e.png') FROM image WHERE name = 'image1';
 raster | lo_export
--------+-----------
  24598 |         1
(1 row)
   
postgres=# \! md5sum /tmp/screenshot.png /tmp/screenshot-e.png
dc51d60215f547a897d4d73beba65ded /tmp/screenshot.png
dc51d60215f547a897d4d73beba65ded /tmp/screenshot-e.png

需要注意的是,在使用 pg_largeobject 来管理大对象时,我们需要额外的操作来管理大对象。例如,上面的示例中,如果我们想要删除表 image 中名称为 image1 的记录,我们还需在 pg_largeobject 中删除 loid = 24598 的记录。如下所示:

sql 复制代码
postgres=# DELETE FROM image WHERE name = 'image1';
DELETE 1
postgres=# SELECT name FROM image;
 name
------
(0 rows)

postgres=# SELECT loid, COUNT(pageno) FROM pg_largeobject GROUP BY loid;
 loid  | count
-------+-------
 24598 |    25
(1 row)
   
postgres=# DELETE FROM pg_largeobject WHERE loid = 24598;
DELETE 25
postgres=# SELECT loid, COUNT(pageno) FROM pg_largeobject GROUP BY loid;
 loid | count
------+-------
(0 rows)

通常,我们会创建一个触发器来进行 OID 的删除。此外,pg_largeobject 提供了 lo_put 和 lo_get 函数来随机读写大对象。需要注意的是,我们在使用 libpq 对大对象进行读写时必须在事务中。

为什么对大对象进行读写时必须在事务中

pg 数据库对于大对象类型的资源进行操作时,必须保证所有的大对象操作函数在同一个SQL事务块中发生,因为大对象类型的文件描述符仅在事务的持续时间内有效

All large object manipulation using these functions must take place within an SQL transaction block, since large object file descriptors are only valid for the duration of a transaction.

PostgreSQL: Documentation: 15: 35.3. Client Interfaces

相关推荐
yangchanghua1111 小时前
pgsql 如何查询今天范围内的数据(当天0点0分0秒 - 当天23点59分59秒....)
数据库·pgsql
larance1 小时前
SQLAlchemy 的异步操作来批量保存对象列表
数据库·python
python_chai1 小时前
从数据汇总到高级分析,SQL 查询进阶实战(下篇)—— 分组、子查询与窗口函数全攻略
数据库·sql·mysql
在努力的前端小白2 小时前
Spring Boot 敏感词过滤组件实现:基于DFA算法的高效敏感词检测与替换
java·数据库·spring boot·文本处理·敏感词过滤·dfa算法·组件开发
未来之窗软件服务2 小时前
自建知识库,向量数据库 (九)之 量化前奏分词服务——仙盟创梦IDE
数据库·仙盟创梦ide·东方仙盟·自建ai·ai分词
冒泡的肥皂5 小时前
MVCC初学demo(一
数据库·后端·mysql
.Shu.6 小时前
Redis Reactor 模型详解【基本架构、事件循环机制、结合源码详细追踪读写请求从客户端连接到命令执行的完整流程】
数据库·redis·架构
薛晓刚9 小时前
当MySQL的int不够用了
数据库
SelectDB技术团队9 小时前
Apache Doris 在菜鸟的大规模湖仓业务场景落地实践
数据库·数据仓库·数据分析·apache doris·菜鸟技术
星空下的曙光10 小时前
mysql 命令语法操作篇 数据库约束有哪些 怎么使用
数据库·mysql