咱们知道在 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 中也会有一条记载大目标的相关元信息,他们的定义如下所示:

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)
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 表中的大目标。例如,咱们创立一个表来存储图片数据,如下所示:

CREATE TABLE image(name text, raster oid);

pg_largeobject 供给了一系列函数用于创立、导入和导出大目标,见官方文档服务端函数。下面是简单的大目标插入导出的测验输出:

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 的记载。如下所示:

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