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

相关推荐
hefaxiang28 分钟前
[Mysql] Mysql的多表查询----多表关系(下)
数据库·mysql
夜魔00943 分钟前
SQLite3 JDBC Java工具类
java·数据库·sqlite·工具类·sqliteutile
m 哆哆.ღ1 小时前
【Python进阶】Python中的数据库交互:使用SQLite进行本地数据存储
数据库·python·交互
EasyCVR1 小时前
ISUP协议视频平台EasyCVR私有化部署视频平台如何实现RTMP推流将大疆无人机的视频画面回传?
服务器·网络·数据库·人工智能·音视频·无人机
OKkankan3 小时前
单链表算法题(数据结构)
c语言·数据结构·数据库·c++·算法
豆 腐3 小时前
MySQL【五】
数据库·笔记·mysql
SAP学习成长之路4 小时前
如何在SM30生成的维护表中增加选择框 CheckBox
开发语言·数据库·sap·健康医疗·abap·代码规范
莳花微语4 小时前
YashanDB 23.2.3安装过程,并使用DBeaver进行连接
数据库
Jm大好时光4 小时前
redis实现消息队列的几种方式
数据库·redis·缓存
勤奋的凯尔森同学4 小时前
Ubuntu24.04上安装和配置MariaDB
android·数据库·mariadb