迁移 Oracle 到 PostgreSQL: 大对象 BLOB

五月 22, 2023

摘要:在本文中,我们将看看 Oracle BLOB 是什么,以及如何将其转换到 PostgreSQL 并使用它。BLOB(二进制大对象)是一种 Oracle 数据类型,用于存储二进制数据(如文件内容)或信息(如音频、视频和图像)。PostgreSQL 没有直接的 BLOB 数据类型,但我们可以使用以下方法使用它。

大对象

大对象是存储在表外部的值。

假设您在 /tmp/ 文件夹下下载了一个图像(jpeg 格式):

$ ls /tmp/test.jpg 
/tmp/test.jpg

我们希望将此图像存储在 PostgreSQL 数据库中。我们可以登录到数据库,执行下面的 SQL 语句:

postgres=# create table test1(n int,n1 oid);
CREATE TABLE

postgres=# insert into test1 values (1,lo_import('/tmp/test.jpg'));
INSERT 0 1

lo_import() 函数将命名文件加载到 pg_largeobject 中,并返回引用大对象的 OID(对象标识符)值。

选择表 test1 将显示 OID,而不是构成此照片的位。

目录 pg_largeobject(系统表)保存构成“大型对象”的数据。大型对象由创建时分配的 OID 标识。每个大对象都分为足够小的段,可以存储为 pg_largeobject 中的行。

每页的数据量是其 LOBLKSIZE(目前为 BLCKSZ / 4,或通常为 2 kB)。

postgres=# select * from test1;
 n |  n1
---+-------
 1 | 16408
(1 row)

postgres=# select distinct loid from pg_largeobject;
 loid
-------
 16408
(1 row)

要查看当前数据库中的所有大对象,我们可以在 psql 终端中使用 “ \lo_list” 命令:

postgres=# \lo_list
         Large objects
  ID   |  Owner   | Description 
-------+----------+-------------
 16408 | postgres | 
(1 row)

使用函数 lo_export(),我们可以将照片写回文件中:

postgres=# SELECT lo_export( 16408, '/tmp/newtest.jpg' );
 lo_export
-----------
         1
(1 row)

使用差异实用程序比较两个文件:

$ diff /tmp/newtest.jpg /tmp/test.jpg
No difference found.

使用函数 lo_unlink(),您可以从数据库中删除大型对象:

postgres=# select lo_unlink(16408);
 lo_unlink
-----------
         1
(1 row)

postgres=# select * from pg_largeobject;
 loid | pageno | data 
------+--------+------

(0 rows)

Bytea 数据类型

bytea 数据类型可用于存储二进制字符串。bytea 的存储大小为 1 或 4 个字节加上实际的二进制字符串。

bytea类型支持I/O(输入)和O/P(输出)两种外部格式:即十六进制和转义格式。这两者都在输入时始终被接受。输出格式取决于称为 bytea_output 的 GUC 参数。此参数的默认值为 hex。

请参考 PostgreSQL 文档中的二进制数据类型,了解有关 bytea 数据类型和格式的更多信息。

假设您在 /tmp/ 文件夹下下载了一个图像(jpeg 格式):

$ ls /tmp/test.jpg
/tmp/test.jpg

我们希望将此图像存储在 PostgreSQL 数据库中。我们可以登录到数据库,执行下面的 SQL 语句:

postgres=# create table test(n int, n1 bytea);
CREATE TABLE

postgres=# insert into test values (1,'/tmp/test.jpg');
INSERT 0 1

postgres=# show bytea_output;
 bytea_output
--------------
 hex
(1 row)

postgres=# select * from test;
 n |              n1
---+------------------------------
 1 | \x2f746d702f746573742e6a7067
(1 row)

postgres=# set bytea_output ='escape';
SET

postgres=# select * from test;
 n |      n1
---+---------------
 1 | /tmp/test.jpg
(1 row)