

# 使用 lo 模块管理大型对象
<a name="PostgreSQL_large_objects_lo_extension"></a>

lo 模块（扩展）适用于通过 JDBC 或 ODBC 驱动程序使用 PostgreSQL 数据库的数据库用户和开发人员。JDBC 和 ODBC 都希望数据库能够在对大型对象的引用发生更改时处理对大型对象的删除。但 PostgreSQL 并非如此。PostgreSQL 并不假定在对于对象的引用发生变化时应该删除该对象。结果是对象保留在磁盘上，未引用。lo 扩展包括一个函数，您可以使用该函数在引用发生变化时触发，以便在需要时删除对象。

**提示**  
要确定数据库是否可以从 lo 扩展中受益，请使用 `vacuumlo` 实用程序检查孤立的大型对象。要在不采取任何操作的情况下获取孤立的大型对象的计数，请使用 `-n` 选项（无操作）运行此实用程序。要了解如何操作，请参阅下面的 [vacuumlo utility](#vacuumlo-utility)。

lo 模块适用于 Aurora PostgreSQL 13.7、12.11、11.16、10.21 及更高的次要版本。

要安装模块（扩展），您需要 `rds_superuser` 权限。安装 lo 扩展会将以下内容添加到数据库中：
+ `lo` – 这是一种大型对象 (lo) 数据类型，可用于二进制大型对象 (BLOB) 和其他大型对象。`lo` 数据类型是 `oid` 数据类型的域。换句话说，它是一个具有可选限制的对象标识符。有关更多信息，请参阅 PostgreSQL 文档中的[对象标识符](https://www.postgresql.org/docs/14/datatype-oid.html)。简单来说，您可以使用 `lo` 数据类型，以区分包含大型对象引用的数据库列与其他对象标识符 (OID)。
+ `lo_manage` – 这是一个函数，您可以在包含大型对象引用的表列上的触发器中使用。无论何时删除或修改引用大型对象的值，触发器都会取消 (`lo_unlink`) 对象与其引用之间的关联。仅当列是对大型对象的唯一数据库引用时，才对列使用触发器。

有关大型对象模块的更多信息，请参阅 PostgreSQL 文档中的 [Lo](https://www.postgresql.org/docs/current/lo.html)。

## 安装 lo 扩展
<a name="PostgreSQL_large_objects_lo_extension.install"></a>

在安装 lo 扩展之前，请确保您具有 `rds_superuser` 权限。

**安装 lo 扩展**

1. 使用 `psql` 连接到 Aurora PostgreSQL 数据库集群的主数据库实例。

   ```
   psql --host=your-cluster-instance-1.666666666666.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password
   ```

   出现提示时请输入密码。`psql` 客户端会建立连接并显示默认的管理连接数据库 `postgres=>`，作为提示符。

1. 按如下方式安装扩展。

   ```
   postgres=> CREATE EXTENSION lo;
   CREATE EXTENSION
   ```

您现在可以使用 `lo` 数据类型定义表中的列。例如，您可以创建包含光栅图像数据的表 (`images`)。您可以对列 `raster` 使用 `lo` 数据类型，如以下示例所示，它将创建一个表。

```
postgres=> CREATE TABLE images (image_name text, raster lo);
```

## 使用 lo\$1manage 触发器函数删除对象
<a name="PostgreSQL_large_objects_lo_extension.using"></a>

在更新或删除 `lo` 时，可以在 `lo` 或其他大型对象列上的触发器中使用 `lo_manage` 函数来清理（并防止出现孤立对象）。

**在引用大型对象的列上设置触发器**
+ 请执行以下操作之一：
  + 对此参数使用列名称，在每个列上创建一个 BEFORE UPDATE OR DELETE 触发器，以包含对大型对象的唯一引用。

    ```
    postgres=> CREATE TRIGGER t_raster BEFORE UPDATE OR DELETE ON images
        FOR EACH ROW EXECUTE FUNCTION lo_manage(raster);
    ```
  + 仅在更新列时才应用触发器。

    ```
    postgres=> CREATE TRIGGER t_raster BEFORE UPDATE OF images
        FOR EACH ROW EXECUTE FUNCTION lo_manage(raster);
    ```

`lo_manage` 触发器函数仅在插入或删除列数据的上下文中起作用，具体取决于您定义触发器的方式。对数据库执行 `DROP` 或 `TRUNCATE` 操作时，它不起作用。这意味着在删除之前应该从任何表中删除对象列，以防止创建孤立的对象。

例如，假设您要删除包含 `images` 表的数据库。您可以按如下方式删除该列。

```
postgres=> DELETE FROM images COLUMN raster
```

假设在该列上定义了用于处理删除 `lo_manage` 的函数，现在可以安全地删除该表。

## 使用 `vacuumlo` 删除孤立的大型对象
<a name="PostgreSQL_large_objects_lo_extension.vacuumlo-utility"></a>

 `vacuumlo` 实用程序识别孤立的大型对象并从数据库中删除它们。此实用程序自 PostgreSQL 9.1.24 以来一直可用。如果数据库用户定期使用大型对象，建议您偶尔运行 `vacuumlo` 来清理孤立的大型对象。

在安装 lo 扩展之前，您可以使用 `vacuumlo` 评估 Aurora PostgreSQL 数据库集群是否可以受益。要执行此操作，请使用 `-n` 选项（无操作）运行 `vacuumlo` 以显示要删除的内容，如下所示：

```
$ vacuumlo -v -n -h your-cluster-instance-1.666666666666.aws-region.rds.amazonaws.com -p 5433 -U postgres docs-lab-spatial-db
Password:*****
Connected to database "docs-lab-spatial-db"
Test run: no large objects will be removed!
Would remove 0 large objects from database "docs-lab-spatial-db".
```

如输出所示，孤立的大型对象对于这个特定的数据库来说并不是问题。

有关此实用程序的更多信息，请参阅 PostgreSQL 文档中的 [https://www.postgresql.org/docs/current/vacuumlo.html](https://www.postgresql.org/docs/current/vacuumlo.html)。

## 了解 `vacuumlo` 的工作方式
<a name="PostgreSQL_large_objects_lo_extension.vacuumlo-remove"></a>

 `vacuumlo` 命令从 PostgreSQL 数据库中删除孤立的大型对象（LO），而不会影响用户表或与用户表冲突。

该命令的工作原理如下：

1. `vacuumlo` 首先创建一个临时表，其中包含数据库中大型对象的所有对象 ID（OID）。

1. 然后，`vacuumlo` 会全面地扫描数据库中使用 `oid` 或 `lo` 数据类型的每一列。如果 `vacuumlo` 在这些列中找到匹配的 OID，则会从临时表中删除该 OID。`vacuumlo` 仅检查专门命名为 `oid` 或 `lo` 的列，而不检查基于这些类型的域。

1. 临时表中的其余条目表示孤立的大型对象，然后 `vacuumlo` 会安全地删除这些大型对象。

## 提高 `vacuumlo` 性能
<a name="PostgreSQL_large_objects_lo_extension.vacuumlo-improve"></a>

 您可以通过使用 `-l` 选项增加批处理大小来提高 `vacuumlo` 的性能。这样将允许 `vacuumlo` 一次处理更多大型对象。

 如果您的系统有足够的内存，并且您可以将临时表完全容纳在内存中，则在数据库级别增加 `temp_buffers` 设置可提高性能。这样有助于表完全驻留在内存中，从而可提高总体性能。

接下来查询会估计临时表的大小：

```
SELECT
    pg_size_pretty(SUM(pg_column_size(oid))) estimated_lo_temp_table_size
FROM
    pg_largeobject_metadata;
```

## 大型对象的注意事项
<a name="PostgreSQL_large_objects_lo_extension.vacuumlo-consider"></a>

接下来，您可以找到在处理大型对象时需要注意的一些重要注意事项：
+ `Vacuumlo` 是唯一的解决方案，因为目前没有其他方法可以删除孤立的大型对象。
+ 使用复制技术的诸如 pglogical、本机逻辑复制和 AWS DMS 等工具不支持复制大型对象。
+ 在设计数据库架构时，请尽可能避免使用大型对象，并考虑改用 `bytea` 等替代数据类型。
+ 定期运行 `vacuumlo`，至少每周一次，以防止孤立的大型对象出现问题。
+ 在存储大型对象的表上使用带有 `lo_manage` 函数的触发器，以帮助防止创建孤立的大型对象。