

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 搭配 Amazon RDS for PostgreSQL 使用 PostgreSQL 擴充功能
<a name="Appendix.PostgreSQL.CommonDBATasks.Extensions"></a>

您可安裝各種擴充功能和模組來擴展 PostgreSQL 的功能。例如，若要使用空間資料，您可以安裝和使用 PostGIS 擴充功能。如需詳細資訊，請參閱 [使用 PostGIS 擴充功能管理空間資料](Appendix.PostgreSQL.CommonDBATasks.PostGIS.md)。另一個例子是，如果要改進極大型資料表的資料輸入，則可以考慮使用 `pg_partman` 擴充功能對資料進行分區。如需詳細資訊，請參閱 [使用 pg\$1partman 擴充功能來管理 PostgreSQL 分割區](PostgreSQL_Partitions.md)。

**注意**  
RDS for PostgreSQL 透過 `pg_tle` 延伸模組支援 PostgreSQL 的受信任語言延伸模組，您可以將其新增至資料庫執行個體。透過使用此延伸模組，開發人員可以在安全環境中建立自己的 PostgreSQL 延伸模組，這會簡化設定和組態需求。若要了解支援 `pg_tle` 延伸模組的 RDS for PostgreSQL 版本以及詳細資訊，請參閱 [使用適用於 PostgreSQL 的受信任語言延伸模組](PostgreSQL_trusted_language_extension.md)。

在某些情況下，您可以將特定模組新增至 RDS for PostgreSQL 資料庫叢集的自訂資料庫叢集參數群組中的 `shared_preload_libraries` 清單，而不是安裝延伸模組。一般而言，預設資料庫叢集參數群組只會載入 `pg_stat_statements`，但有數個其他模組可供新增至清單。例如，您可以新增 `pg_cron` 模組來新增排程功能，如[使用 PostgreSQL pg\$1cron 擴充功能排程維護](PostgreSQL_pg_cron.md)中所詳述。另一個範例是，您可以載入 `auto_explain` 模組來記錄查詢執行計劃。若要進一步了解，請參閱 AWS 知識中心的[記錄查詢的執行計畫](https://aws.amazon.com/premiumsupport/knowledge-center/rds-postgresql-tune-query-performance/#)。

根據 RDS for PostgreSQL 版本，安裝擴充功能可能需要 `rds_superuser` 許可權限，如下：
+ 若為 RDS for PostgreSQL 第 12 版和更早版本，安裝擴充功能需要 `rds_superuser` 權限。
+ 若為 RDS for PostgreSQL 第 13 版和更新版本，在給定資料庫執行個體上具建立許可權限的使用者 (角色) 可以安裝並使用任何*信任擴充功能*。如需信任擴充功能的清單，請參閱 [PostgreSQL 可信任延伸](PostgreSQL.Concepts.General.FeatureSupport.Extensions.md#PostgreSQL.Concepts.General.Extensions.Trusted)。

您還可在 `rds.allowed_extensions` 參數中列出擴充功能，精確指定可在 RDS for PostgreSQL 資料庫執行個體上安裝的擴充功能。如需詳細資訊，請參閱[限制安裝 PostgreSQL 擴充功能](PostgreSQL.Concepts.General.FeatureSupport.Extensions.md#PostgreSQL.Concepts.General.FeatureSupport.Extensions.Restriction)。

若要進一步了解 `rds_superuser` 角色，請參閱 [了解 PostgreSQL 角色和許可](Appendix.PostgreSQL.CommonDBATasks.Roles.md)。

**Topics**
+ [使用 Orafce 擴充功能中的函數](Appendix.PostgreSQL.CommonDBATasks.orafce.md)
+ [使用 PostgreSQL 的 Amazon RDS 委派延伸模組支援](RDS_delegated_ext.md)
+ [使用 pg\$1partman 擴充功能來管理 PostgreSQL 分割區](PostgreSQL_Partitions.md)
+ [使用 PgAudit 記錄資料庫活動](Appendix.PostgreSQL.CommonDBATasks.pgaudit.md)
+ [使用 PostgreSQL pg\$1cron 擴充功能排程維護](PostgreSQL_pg_cron.md)
+ [使用 pglogical 跨執行個體同步資料](Appendix.PostgreSQL.CommonDBATasks.pglogical.md)
+ [使用 pgactive 來支援主動-主動式複寫](Appendix.PostgreSQL.CommonDBATasks.pgactive.md)
+ [使用 pg\$1repack 擴充功能減少資料表和索引膨脹](Appendix.PostgreSQL.CommonDBATasks.pg_repack.md)
+ [升級和使用 PLV8 擴充功能](PostgreSQL.Concepts.General.UpgradingPLv8.md)
+ [使用 PL/Rust 以 Rust 語言撰寫 PostgreSQL 函數](PostgreSQL.Concepts.General.Using.PL_Rust.md)
+ [使用 PostGIS 擴充功能管理空間資料](Appendix.PostgreSQL.CommonDBATasks.PostGIS.md)

# 使用 Orafce 擴充功能中的函數
<a name="Appendix.PostgreSQL.CommonDBATasks.orafce"></a>

Orafce 擴充功能提供的函數和運算子，可以模擬來自 Oracle 資料庫的函數和軟體套件的子集合。Orafce 擴充功能可讓您更輕易地將 Oracle 應用程式移植到 PostgreSQL。RDS for PostgreSQL 9.6.6 版及更高版本支援此擴充功能。如需有關 Orafce 的詳細資訊，請參閱 GitHub 上的 [Orafce](https://github.com/orafce/orafce)。

**注意**  
RDS for PostgreSQL 不支援 `utl_file` 套件，該套件屬於 Orafce 擴充功能的一部分。這是因為 `utl_file` 結構描述函式雖能夠在作業系統的文字檔上進行讀取及寫入操作，但必須擁有基礎主機的超級使用者存取權，才能執行此類操作。RDS for PostgreSQL 為受管服務，不提供主機存取權。

**使用 Orafce 擴充功能**

1. 使用您用來建立資料庫執行個體的主要使用者名稱，來連線至資料庫執行個體。

   如果您想要在相同的資料庫執行個體中為不同的資料庫開啟 Orafce，請使用 `/c dbname` psql 命令。使用此命令，您可以在啟動連線後從主要資料庫進行變更。

1. 使用 `CREATE EXTENSION` 陳述式開啟 Orafce 擴充功能。

   ```
   CREATE EXTENSION orafce;
   ```

1. 使用 `ALTER SCHEMA` 陳述式將 oracle 結構描述的擁有權移轉至 rds\$1superuser 角色。

   ```
   ALTER SCHEMA oracle OWNER TO rds_superuser;
   ```

   如果您想要查看 oracle 結構描述的擁有者清單，請使用 `\dn` psql 命令。

# 使用 PostgreSQL 的 Amazon RDS 委派延伸模組支援
<a name="RDS_delegated_ext"></a>

使用 PostgreSQL 的 Amazon RDS 委派延伸模組支援，您可以將延伸模組管理委派給非 `rds_superuser` 的使用者。系統會透過此委派延伸模組支援，建立名為 `rds_extension` 的新角色，而您必須將此角色指派給使用者以管理其他延伸模組。此角色可以建立、更新和捨棄延伸模組。

您可在 `rds.allowed_extensions` 參數中列出延伸模組，藉以指定可在 RDS 資料庫執行個體上安裝的延伸模組。如需詳細資訊，請參閱[將 PostgreSQL 延伸模組與 Amazon RDS for PostgreSQL 搭配使用](https://docs.aws.amazon.com//AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Extensions.html)。

您可以使用 `rds.allowed_delegated_extensions` 參數，限制可由具有 `rds_extension` 角色的使用者所管理的可用延伸模組清單。

您可在下列版本中取得委派的延伸模組支援：
+ 所有更高版本
+ 16.4 和更高的第 16 版
+ 15.8 和更高的第 15 版
+ 14.13 和更高的第 14 版
+ 13.16 和更高的第 13 版
+ 12.20 和更高的第 12 版

**Topics**
+ [為使用者開啟委派延伸模組支援](#RDSPostgreSQL.delegated_ext_mgmt)
+ [在 PostgreSQL 的 RDS 委派延伸模組支援中使用的組態](#RDSPostgreSQL.delegated_ext_config)
+ [關閉委派延伸模組的支援](#RDSPostgreSQL.delegated_ext_disable)
+ [使用 Amazon RDS 委派延伸模組支援的優點](#RDSPostgreSQL.delegated_ext_benefits)
+ [PostgreSQL 的 Amazon RDS 委派延伸模組支援限制](#RDSPostgreSQL.delegated_ext_limit)
+ [特定延伸模組所需的許可](#RDSPostgreSQL.delegated_ext_perm)
+ [安全考量](#RDSPostgreSQL.delegated_ext_sec)
+ [已停用捨棄延伸模組層疊](#RDSPostgreSQL.delegated_ext_drop)
+ [可使用委派延伸模組支援新增的延伸模組範例](#RDSPostgreSQL.delegated_ext_support)

## 為使用者開啟委派延伸模組支援
<a name="RDSPostgreSQL.delegated_ext_mgmt"></a>

您必須執行下列動作，才能將延伸模組支援委派給使用者：

1. **將 `rds_extension` 角色授予使用者**：以 `rds_superuser` 身分連線至資料庫，以及執行下列命令：

   ```
   Postgres => grant rds_extension to user_name;
   ```

1. **設定可供委派使用者管理的延伸模組清單**：`rds.allowed_delegated_extensions` 可讓您在資料庫叢集參數中使用 `rds.allowed_extensions` 指定可用延伸模組子集。您可以在下列其中一個層級執行此操作：
   + 在叢集或執行個體參數群組中，透過 AWS 管理主控台 或 API。如需詳細資訊，請參閱[Amazon RDS 的參數群組](USER_WorkingWithParamGroups.md)。
   + 在資料庫層級使用以下命令：

     ```
     alter database database_name set rds.allowed_delegated_extensions = 'extension_name_1,
                         extension_name_2,...extension_name_n';
     ```
   + 在使用者層級使用以下命令：

     ```
     alter user user_name set rds.allowed_delegated_extensions = 'extension_name_1,
                         extension_name_2,...extension_name_n';
     ```
**注意**  
變更 `rds.allowed_delegated_extensions` 動態參數後，您就不需要重新啟動資料庫。

1. **允許委派使用者存取在延伸模組建立程序期間建立的物件**：某些延伸模組會建立需要授予額外許可的物件，才能讓具有 `rds_extension` 角色的使用者存取這些物件。`rds_superuser` 必須向委派的使用者授予對那些物件的存取權。其中一個選項是使用事件觸發，自動將許可授予委派的使用者。

   **事件觸發範例**

   如要允許具備 `rds_extension` 的委派使用者使用延伸模組，而這些延伸模組需要針對延伸模組建立的物件設定許可，您可以自訂下列事件觸發範例，並僅新增您希望委派使用者能夠存取完整功能的延伸模組。系統可以在 template1 (預設範本) 建立此事件觸發，因此從 template1 建立的所有資料庫都會具有該事件觸發。當委派的使用者安裝此延伸模組時，此觸發會針對延伸模組建立的物件自動授予擁有權。

   ```
   CREATE OR REPLACE FUNCTION create_ext()
   
     RETURNS event_trigger AS $$
   
   DECLARE
   
     schemaname TEXT;
     databaseowner TEXT;
   
     r RECORD;
   
   BEGIN
   
     IF tg_tag = 'CREATE EXTENSION' and current_user != 'rds_superuser' THEN
       RAISE NOTICE 'SECURITY INVOKER';
       RAISE NOTICE 'user: %', current_user;
       FOR r IN SELECT * FROM pg_catalog.pg_event_trigger_ddl_commands()
       LOOP
           CONTINUE WHEN r.command_tag != 'CREATE EXTENSION' OR r.object_type != 'extension';
   
           schemaname = (
               SELECT n.nspname
               FROM pg_catalog.pg_extension AS e
               INNER JOIN pg_catalog.pg_namespace AS n
               ON e.extnamespace = n.oid
               WHERE e.oid = r.objid
           );
   
           databaseowner = (
               SELECT pg_catalog.pg_get_userbyid(d.datdba)
               FROM pg_catalog.pg_database d
               WHERE d.datname = current_database()
           );
           RAISE NOTICE 'Record for event trigger %, objid: %,tag: %, current_user: %, schema: %, database_owenr: %', r.object_identity, r.objid, tg_tag, current_user, schemaname, databaseowner;
           IF r.object_identity = 'address_standardizer_data_us' THEN
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_gaz TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_lex TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_rules TO %I WITH GRANT OPTION;', schemaname, databaseowner);
           ELSIF r.object_identity = 'dict_int' THEN
               EXECUTE pg_catalog.format('ALTER TEXT SEARCH DICTIONARY %I.intdict OWNER TO %I;', schemaname, databaseowner);
           ELSIF r.object_identity = 'pg_partman' THEN
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.part_config TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.part_config_sub TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.custom_time_partitions TO %I WITH GRANT OPTION;', schemaname, databaseowner);
           ELSIF r.object_identity = 'postgis_topology' THEN
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON ALL TABLES IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
               EXECUTE pg_catalog.format('GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
               EXECUTE pg_catalog.format('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
               EXECUTE pg_catalog.format('GRANT USAGE ON SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
           END IF;
       END LOOP;
     END IF;
   END;
   $$ LANGUAGE plpgsql SECURITY DEFINER;
   
   CREATE EVENT TRIGGER log_create_ext ON ddl_command_end EXECUTE PROCEDURE create_ext();
   ```

## 在 PostgreSQL 的 RDS 委派延伸模組支援中使用的組態
<a name="RDSPostgreSQL.delegated_ext_config"></a>


| 組態名稱 | Description | 預設值 | 備註 | 誰可以修改或授予許可 | 
| --- | --- | --- | --- | --- | 
| `rds.allowed_delegated_extensions` | 此參數會限制 rds\$1extension 角色可在資料庫中管理的延伸模組。其必須是 rds.allowed\$1extensions 的子集。 | 空字串 | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/RDS_delegated_ext.html) 若要進一步了解如何設定此參數，請參閱[為使用者開啟委派延伸模組支援](#RDSPostgreSQL.delegated_ext_mgmt)。 | rds\$1superuser | 
| `rds.allowed_extensions` | 此參數可讓客戶限制 RDS 資料庫執行個體中可安裝的延伸模組。如需詳細資訊，請參閱[限制安裝 PostgreSQL 延伸模組](https://docs.aws.amazon.com//AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts.General.FeatureSupport.Extensions.Restriction)。 | "\$1" | 根據預設，此參數會設為「\$1」，這表示具有必要權限的使用者都能夠建立 RDS for PostgreSQL 和 Aurora PostgreSQL 上支援的所有延伸模組。 空白表示無法在 RDS 資料庫執行個體中安裝任何延伸模組。 | 管理員 | 
| `rds-delegated_extension_allow_drop_cascade` | 此參數會控制具有 `rds_extension` 的使用者是否能使用層疊選項捨棄延伸模組。 | off | 根據預設，`rds-delegated_extension_allow_drop_cascade` 會設定為 `off`。這表示具有 `rds_extension` 的使用者無法使用層疊選項捨棄延伸模組。 若要授予該能力，則應將 `rds.delegated_extension_allow_drop_cascade` 參數設為 `on`。 | rds\$1superuser | 

## 關閉委派延伸模組的支援
<a name="RDSPostgreSQL.delegated_ext_disable"></a>

**部分關閉**  
委派的使用者無法建立新的延伸模組，但仍可以更新現有的延伸模組。
+ 將資料庫叢集參數群組中的 `rds.allowed_delegated_extensions` 重設為預設值。
+ 在資料庫層級使用以下命令：

  ```
  alter database database_name reset rds.allowed_delegated_extensions;
  ```
+ 在使用者層級使用以下命令：

  ```
  alter user user_name reset rds.allowed_delegated_extensions;
  ```

**完全關閉**  
從使用者撤銷 `rds_extension` 角色會將使用者還原為標準許可。使用者無法再建立、更新或捨棄延伸模組。

```
postgres => revoke rds_extension from user_name;
```

## 使用 Amazon RDS 委派延伸模組支援的優點
<a name="RDSPostgreSQL.delegated_ext_benefits"></a>

藉由使用 PostgreSQL 的 Amazon RDS 委派延伸模組支援，您就可以將延伸模組管理安全地委派給不具備 `rds_superuser` 角色的使用者。此功能提供下列優勢：
+ 您可以輕鬆地將延伸模組管理委派給所選的使用者。
+ 這不需要 `rds_superuser` 角色。
+ 提供支援相同資料庫叢集中不同資料庫不同延伸模組集的能力。

## PostgreSQL 的 Amazon RDS 委派延伸模組支援限制
<a name="RDSPostgreSQL.delegated_ext_limit"></a>
+ 在延伸模組建立程序期間建立的物件可能需要額外的權限，延伸模組才能正常運作。
+ 根據預設，委派的延伸模組使用者無法管理某些延伸模組，包括：`log_fdw`、`pg_cron`、`pg_tle`、`pgactive``pglogical`、`postgis_raster`、`postgis_tiger_geocoder`、`postgis_topology`。

## 特定延伸模組所需的許可
<a name="RDSPostgreSQL.delegated_ext_perm"></a>

為了建立、使用或更新下列延伸模組，委派的使用者應具備下列功能、資料表和結構描述的必要權限。


| 需要擁有權或許可的延伸模組 | 函式 | 表格 | 結構描述 | 文字搜尋字典 | Comment | 
| --- | --- | --- | --- | --- | --- | 
| address\$1standardizer\$1data\$1us | 無 | us\$1gaz、us\$1lex、us\$1lex、I.us\$1rules | 無 | 無 | 無 | 
| amcheck | bt\$1index\$1check、bt\$1index\$1parent\$1check | 無 | 無 | 無 | 無 | 
| dict\$1int | 無 | 無 | 無 | intdict | 無 | 
| pg\$1partman | 無 | custom\$1time\$1partitions、part\$1config、part\$1config\$1sub | 無 | 無 | 無 | 
| pg\$1stat\$1statements | 無 | 無 | 無 | 無 | 無 | 
| PostGIS | st\$1tileenvelope | spatial\$1ref\$1sys | 無 | 無 | 無 | 
| postgis\$1raster | 無 | 無 | 無 | 無 | 無 | 
| postgis\$1topology | 無 | 拓撲、層 | 拓撲 | 無 | 委派使用者必須是資料庫擁有者 | 
| log\$1fdw | create\$1foreign\$1table\$1for\$1log\$1file | 無 | 無 | 無 | 無 | 
| rds\$1tools | role\$1password\$1encryption\$1type | 無 | 無 | 無 | 無 | 
| postgis\$1tiger\$1geocoder | 無 | geocode\$1settings\$1default、geocode\$1settings | tiger | 無 | 無 | 
| pg\$1freespacemap | pg\$1freespace | 無 | 無 | 無 | 無 | 
| pg\$1visibility | pg\$1visibility | 無 | 無 | 無 | 無 | 

## 安全考量
<a name="RDSPostgreSQL.delegated_ext_sec"></a>

 請記住，具有 `rds_extension` 角色的使用者將能夠在其具有連線權限的所有資料庫上管理延伸模組。若需讓委派使用者管理單一資料庫的延伸模組，良好做法是撤銷每個資料庫上公有的所有權限，然後明確將該特定資料庫的連線權限授予委派的使用者。

 有多種延伸模組，使用者可透過這些延伸模組從多個資料庫存取資訊。在將這些延伸模組新增至 `rds.allowed_delegated_extensions` 前，請確定您授予 `rds_extension` 的使用者具有跨資料庫功能。例如，`postgres_fdw` 和 `dblink` 會提供在相同執行個體或遠端執行個體上跨資料庫查詢的功能。`log_fdw` 會讀取適用於執行個體中所有資料庫的 postgres 引擎日誌檔案，可能包含來自多個資料庫的緩慢查詢或錯誤訊息。`pg_cron` 會在資料庫執行個體上執行排程背景任務，並可將任務設定為在不同的資料庫中執行。

## 已停用捨棄延伸模組層疊
<a name="RDSPostgreSQL.delegated_ext_drop"></a>

 具有 `rds_extension` 角色的使用者是否能捨棄具有層疊選項的延伸模組，由 `rds.delegated_extension_allow_drop_cascade` 參數所控制。根據預設，`rds-delegated_extension_allow_drop_cascade` 會設定為 `off`。如以下查詢所示，這表示具有 `rds_extension` 角色的使用者不能使用層疊選項捨棄延伸模組。

```
DROP EXTENSION CASCADE;
```

因為這會自動捨棄相依於延伸模組的物件，進而捨棄所有相依於這些物件的物件。嘗試使用層疊選項將導致錯誤。

 若要授予該能力，則應將 `rds.delegated_extension_allow_drop_cascade` 參數設為 `on`。

 變更 `rds.delegated_extension_allow_drop_cascade` 動態參數不需要重新啟動資料庫。您可以在以下其中一個層級執行此操作：
+ 在叢集或執行個體參數群組中，透過 AWS 管理主控台 或 API。
+ 在資料庫層級使用下列命令：

  ```
  alter database database_name set rds.delegated_extension_allow_drop_cascade = 'on';
  ```
+ 在使用者層級使用下列命令：

  ```
  alter role tenant_user set rds.delegated_extension_allow_drop_cascade = 'on';
  ```

## 可使用委派延伸模組支援新增的延伸模組範例
<a name="RDSPostgreSQL.delegated_ext_support"></a>
+ `rds_tools`

  ```
  extension_test_db=> create extension rds_tools;
  CREATE EXTENSION
  extension_test_db=> SELECT * from rds_tools.role_password_encryption_type() where rolname = 'pg_read_server_files';
  ERROR: permission denied for function role_password_encryption_type
  ```
+ `amcheck`

  ```
  extension_test_db=> CREATE TABLE amcheck_test (id int);
  CREATE TABLE
  extension_test_db=> INSERT INTO amcheck_test VALUES (generate_series(1,100000));
  INSERT 0 100000
  extension_test_db=> CREATE INDEX amcheck_test_btree_idx ON amcheck_test USING btree (id);
  CREATE INDEX
  extension_test_db=> create extension amcheck;
  CREATE EXTENSION
  extension_test_db=> SELECT bt_index_check('amcheck_test_btree_idx'::regclass);
  ERROR: permission denied for function bt_index_check
  extension_test_db=> SELECT bt_index_parent_check('amcheck_test_btree_idx'::regclass);
  ERROR: permission denied for function bt_index_parent_check
  ```
+ `pg_freespacemap`

  ```
  extension_test_db=> create extension pg_freespacemap;
  CREATE EXTENSION
  extension_test_db=> SELECT * FROM pg_freespace('pg_authid');
  ERROR: permission denied for function pg_freespace
  extension_test_db=> SELECT * FROM pg_freespace('pg_authid',0);
  ERROR: permission denied for function pg_freespace
  ```
+ `pg_visibility`

  ```
  extension_test_db=> create extension pg_visibility;
  CREATE EXTENSION
  extension_test_db=> select * from pg_visibility('pg_database'::regclass);
  ERROR: permission denied for function pg_visibility
  ```
+ `postgres_fdw`

  ```
  extension_test_db=> create extension postgres_fdw;
  CREATE EXTENSION
  extension_test_db=> create server myserver foreign data wrapper postgres_fdw options (host 'foo', dbname 'foodb', port '5432');
  ERROR: permission denied for foreign-data wrapper postgres_fdw
  ```

# 使用 pg\$1partman 擴充功能來管理 PostgreSQL 分割區
<a name="PostgreSQL_Partitions"></a>

PostgreSQL 表格分割區提供了用於高性能處理資料輸入和報告的框架。對需要非常快速輸入大量資料的資料庫使用分割區。分割區還提供了更快的大型表格查詢。分割區有助於維護資料，而不會影響資料庫執行個體，因為它需要較少的輸入/輸出資源。

透過使用分割區，您可以將資料分割為自訂大小的區塊進行處理。例如，您可以分割時間序列資料，例如每小時、每日、每週、每月、每季、年度、自訂或以上任何組合。對於時間序列資料範例，如果您依小時分割資料表，則每個分割區都將包含一小時的資料。如果您依每日分割時間序列資料表，則每個分割區將保存一天的資料，依此類推。分割區索引鍵控制分割區的大小。

當您在分割表格上使用 `INSERT` 或 `UPDATE` SQL 命令時，資料庫引擎會將資料路由至適當的分割區。儲存資料的 PostgreSQL 表格分割區是主表格的子表格。

在資料庫查詢讀取期間，PostgreSQL 最佳化器會檢查查詢的 `WHERE` 子句，如果可能的話，將資料庫掃描導向僅相關的分割區。

從 10 版開始，PostgreSQL 使用宣告式分割來實作資料表分割區。這也被稱為原生 PostgreSQL 分割區。在 PostgreSQL 10 版之前，您已使用觸發器來實作分割區。

PostgreSQL 表格分割區提供下列功能：
+ 隨時建立新的分割區。
+ 可變的分割區範圍。
+ 使用資料定義語言 (DDL) 陳述式的可分離和可重新連接分割區。

  例如，可拆分的分割區對於從主磁碟分割區移除歷史資料，但保留歷史資料以供分析來說十分實用。
+ 新的分割區會繼承父資料庫表格屬性，包括以下各項：
  + 索引
  + 主索引鍵，其中必須包含分割區索引鍵資料欄
  + 外部索引鍵
  + 檢查限制
  + 參考
+ 建立完整資料表或每個特定分割區的索引。

您無法變更個別分割區的結構描述。不過，您可以變更父資料表格 (例如新增新資料欄)，此表格會傳播到分割區。

**Topics**
+ [PostgreSQL pg\$1partman 擴充功能概述](#PostgreSQL_Partitions.pg_partman)
+ [啟用 pg\$1partman 擴充功能](#PostgreSQL_Partitions.enable)
+ [使用 create\$1parent 函數設定分割區](#PostgreSQL_Partitions.create_parent)
+ [使用 run\$1maintenance\$1proc 函數來設定分割區維護](#PostgreSQL_Partitions.run_maintenance_proc)

## PostgreSQL pg\$1partman 擴充功能概述
<a name="PostgreSQL_Partitions.pg_partman"></a>

您可以使用 PostgreSQL `pg_partman` 擴充功能，以自動化資料表分割區的建立和維護。如需更多一般資訊，請參閱 `pg_partman` 文件中的 [PG 分割區管理員](https://github.com/pgpartman/pg_partman)。

**注意**  
RDS for PostgreSQL 版本 12.5 及更新版本支援此 `pg_partman` 擴充功能。

您可以使用下列設定來設定 `pg_partman`，而不必手動建立每個分割區：
+ 要分割的表格
+ 分割區類型
+ 分割區索引鍵
+ 分割區間隔
+ 分割區預先建立與管理選項

建立 PostgreSQL 分割區資料表之後，您可以透過呼叫 `create_parent` 函數，使用 `pg_partman` 進行註冊。這樣做會根據您傳遞給函數的參數來建立必要的分割區。

`pg_partman` 擴充功能還提供 `run_maintenance_proc` 函數，您可以按排程呼叫它以自動管理分割區。為了確保視需要建立適當的分割區，可以排程此函數定期執行 (例如每小時)。您還可以確保自動捨棄分割區。

## 啟用 pg\$1partman 擴充功能
<a name="PostgreSQL_Partitions.enable"></a>

如果您要管理相同 PostgreSQL 資料庫執行個體內多個資料庫的分割區，則必須分別為每個資料庫啟用 `pg_partman` 擴充功能。若要啟用特定資料庫的 `pg_partman` 擴充功能，請建立分割區維護結構描述，然後建立 `pg_partman` 擴充功能，如下所示。

```
CREATE SCHEMA partman;
CREATE EXTENSION pg_partman WITH SCHEMA partman;
```

**注意**  
若要建立 `pg_partman` 擴充功能，請確定您具有 `rds_superuser` 權限。

如果您收到下列錯誤訊息，請將`rds_superuser`權限授與帳戶或使用您的超級使用者帳戶。

```
ERROR: permission denied to create extension "pg_partman"
HINT: Must be superuser to create this extension.
```

若要授予 `rds_superuser` 權限，請連線至您的超級使用者帳戶並執行下列命令。

```
GRANT rds_superuser TO user-or-role;
```

以顯示使用 pg\$1partman 擴充功能舉例，我們使用下面的範例資料庫表和分割區。此資料庫使用以時間戳記為基礎的分割表格。結構描述`data_mart`包含一個名為`events`的表格和一個名為`created_at`的欄。下列設定包含在`events`表格中：
+  主索引鍵`event_id`和`created_at`，必須有用於引導分割區的欄。
+ 強制執行`ck_valid_operation`表格欄值的檢查約束`operation`。
+ 兩個外鍵，其中一個（`fk_orga_membership)`）指向外部表格`organization`，另一個（`fk_parent_event_id`）是自引用的外鍵。
+ 兩個索引，其中一個（`idx_org_id`）用於外鍵，另一個（`idx_event_type`）用於事件類型。

下列 DDL 陳述式會建立這些物件，這些物件會自動包含在每個分割區上。

```
CREATE SCHEMA data_mart;
CREATE TABLE data_mart.organization ( org_id BIGSERIAL,
        org_name TEXT,
        CONSTRAINT pk_organization PRIMARY KEY (org_id)  
    );

CREATE TABLE data_mart.events(
        event_id        BIGSERIAL, 
        operation       CHAR(1), 
        value           FLOAT(24), 
        parent_event_id BIGINT, 
        event_type      VARCHAR(25), 
        org_id          BIGSERIAL, 
        created_at      timestamp, 
        CONSTRAINT pk_data_mart_event PRIMARY KEY (event_id, created_at), 
        CONSTRAINT ck_valid_operation CHECK (operation = 'C' OR operation = 'D'), 
        CONSTRAINT fk_orga_membership 
            FOREIGN KEY(org_id) 
            REFERENCES data_mart.organization (org_id),
        CONSTRAINT fk_parent_event_id 
            FOREIGN KEY(parent_event_id, created_at) 
            REFERENCES data_mart.events (event_id,created_at)
    ) PARTITION BY RANGE (created_at);

CREATE INDEX idx_org_id     ON  data_mart.events(org_id);
CREATE INDEX idx_event_type ON  data_mart.events(event_type);
```



## 使用 create\$1parent 函數設定分割區
<a name="PostgreSQL_Partitions.create_parent"></a>

啟用 `pg_partman` 擴充功能之後，可以使用此 `create_parent` 函數來設定在分割維護結構描述內的分割區。以下範例使用在 `events` 中建立的 [啟用 pg\$1partman 擴充功能使用 run\$1maintenance\$1proc 函數來設定分割區維護](#PostgreSQL_Partitions.enable) 資料表範例。如下所示呼叫 `create_parent` 函數。

```
SELECT partman.create_parent( 
 p_parent_table => 'data_mart.events',
 p_control      => 'created_at',
 p_type         => 'range',
 p_interval     => '1 day',
 p_premake      => 30);
```

參數如下：
+ `p_parent_table` – 父項分割表格。此表必須已經存在，並且完全符合資格 (包括結構描述)。
+ `p_control` – 分割區依據的欄。資料類型必須是整數或以時間為基礎。
+ `p_type` – 類型可以是 `'range'` 或 `'list'`。
+ `p_interval` – 每個分割區的時間間隔或整數範圍。範例值包括 `1 day`、`1 hour` 等。
+ `p_premake` – 預先建立以支援新插入的分割區數目。

如需 `create_parent` 函數的完整描述，請參閱 `pg_partman` 文件中的[建立函數](https://github.com/pgpartman/pg_partman/blob/master/doc/pg_partman.md#user-content-creation-functions)。

## 使用 run\$1maintenance\$1proc 函數來設定分割區維護
<a name="PostgreSQL_Partitions.run_maintenance_proc"></a>

您可以執行分割區維護作業以自動建立新的分割區、分離分割區或移除舊的分割區。分割區維護依賴 `pg_partman` 擴充功能的 `run_maintenance_proc` 函數和 `pg_cron` 擴充功能，它們可以啟動內部排程器。`pg_cron`排程器會自動執行資料庫中定義的 SQL 陳述式、函數和程序。

下列範例使用中建立於`events`中的[啟用 pg\$1partman 擴充功能使用 run\$1maintenance\$1proc 函數來設定分割區維護](#PostgreSQL_Partitions.enable)表格範例，將分割區維護作業設定為自動執行。作為必要條件，將 `pg_cron` 新增至資料庫執行個體的參數群組中的 `shared_preload_libraries` 參數。

```
CREATE EXTENSION pg_cron;

UPDATE partman.part_config 
SET infinite_time_partitions = true,
    retention = '3 months', 
    retention_keep_table=true 
WHERE parent_table = 'data_mart.events';
SELECT cron.schedule('@hourly', $$CALL partman.run_maintenance_proc()$$);
```

您可以在下面找到上述範例的逐步說明：

1. 修改與資料庫執行個體關聯的參數群組，並新增`pg_cron`至`shared_preload_libraries`參數值。此變更需要重新啟動資料庫執行個體才能生效。如需詳細資訊，請參閱 [修改 Amazon RDS 中的資料庫參數群組中的參數](USER_WorkingWithParamGroups.Modifying.md)。

1. 使用具有 `CREATE EXTENSION pg_cron;` 許可的帳戶執行命令 `rds_superuser`。這會啟用 `pg_cron` 擴充功能。如需詳細資訊，請參閱 [使用 PostgreSQL pg\$1cron 擴充功能排程維護](PostgreSQL_pg_cron.md)。

1. 執行命令 `UPDATE partman.part_config` 以調整 `data_mart.events` 資料表的 `pg_partman` 設定。

1. 執行 `SET` . . . 命令 以使用這些子句設定 `data_mart.events` 資料表：

   1. `infinite_time_partitions = true,` – 將表格設定為能夠沒有任何限制，自動建立新的分割區。

   1. `retention = '3 months',` – 將表格設定為最多保留三個月。

   1. `retention_keep_table=true `– 設定資料表，以便在保留期限到期時，資料表不會自動刪除。相反地，比保留期間還舊的分割區只會從父表格分離。

1. 執行 `SELECT cron.schedule` . . . 命令 進行 `pg_cron` 函數呼叫。此呼叫定義排程器執行 `pg_partman` 維護程序 `partman.run_maintenance_proc` 的頻率。在此範例中，程序會每小時執行一次。

如需 `run_maintenance_proc` 函數的完整描述，請參閱 `pg_partman` 文件中的[維護函數](https://github.com/pgpartman/pg_partman/blob/master/doc/pg_partman.md#maintenance-functions)。

# 使用 PgAudit 記錄資料庫活動
<a name="Appendix.PostgreSQL.CommonDBATasks.pgaudit"></a>

金融機構、政府機構和許多產業都需要保留「稽核日誌」**，以符合法規要求。透過使用 PostgreSQL 稽核擴充功能 (PgAudit) 搭配 RDS for PostgreSQL 資料庫執行個體，您可以擷取稽核人員通常需要的詳細記錄，以符合法規要求。例如，您可以設定 pgAudit 擴充功能來追蹤對特定資料庫和資料表所做的變更、記錄進行變更的使用者，以及許多其他詳細資訊。

pgAudit 擴充功能建置在原生 PostgreSQL 記錄基礎結構的功能之上，以更多的詳細資訊擴充日誌訊息。換言之，您可以使用與檢視任何日誌訊息相同的方法來檢視稽核日誌。如需 PostgreSQL 記錄的詳細資訊，請參閱 [ RDS for PostgreSQL 資料庫日誌檔案](USER_LogAccess.Concepts.PostgreSQL.md)。

pgAudit 擴充功能會從日誌中刪減敏感資料，例如純文字密碼。如果您的 RDS for PostgreSQL 資料庫執行個體設定為記錄資料操作語言 (DML) 陳述式 (如[開啟 RDS for PostgreSQL 資料庫執行個體的查詢記錄](USER_LogAccess.Concepts.PostgreSQL.Query_Logging.md)中所述)，您可以使用 PostgreSQL 稽核擴充功能避免純文字密碼問題。

您可以非常具體地設定對資料庫執行個體的稽核。您可以稽核所有資料庫和所有使用者。或者，您可以選擇僅稽核某些資料庫、使用者和其他物件。您也可以明確排除特定使用者和資料庫，使其不受稽核。如需更多詳細資訊，請參閱 [從稽核記錄中排除使用者或資料庫](Appendix.PostgreSQL.CommonDBATasks.pgaudit.exclude-user-db.md)。

鑑於可以擷取的詳細資訊量，我們建議您，如果的確使用 pgAudit，請監控您的儲存耗用量。

所有可用的 RDS for PostgreSQL 版本。如需可用的 RDS for PostgreSQL 版本支援的 pgSQL 版本清單，請參閱《Amazon RDS for PostgreSQL 版本資訊》**中的 [Amazon RDS for PostgreSQL 的擴充功能版本。](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html)

**Topics**
+ [設定 pgAudit 擴充功能](Appendix.PostgreSQL.CommonDBATasks.pgaudit.basic-setup.md)
+ [稽核資料庫物件](Appendix.PostgreSQL.CommonDBATasks.pgaudit.auditing.md)
+ [從稽核記錄中排除使用者或資料庫](Appendix.PostgreSQL.CommonDBATasks.pgaudit.exclude-user-db.md)
+ [pgAudit 擴充功能的參考](Appendix.PostgreSQL.CommonDBATasks.pgaudit.reference.md)

# 設定 pgAudit 擴充功能
<a name="Appendix.PostgreSQL.CommonDBATasks.pgaudit.basic-setup"></a>

若要在 RDS for PostgreSQL 資料庫執行個體上設定 PgAudit 擴充功能，您必須先將 PgAudit 新增至 RDS for PostgreSQL 資料庫執行個體的自訂資料庫參數群組上的共用程式庫。如需建立自訂資料庫叢集參數群組的相關資訊，請參閱 [Amazon RDS 的參數群組](USER_WorkingWithParamGroups.md)。接下來，您會安裝 pgAudit 擴充功能。最後，您會指定要稽核的資料庫和物件。本節中的程序展示做法。您可以使用 AWS 管理主控台 或 AWS CLI。

您必須具有做為 `rds_superuser` 角色的許可，才能執行所有這些任務。

以下步驟假設您的 RDS for PostgreSQL 資料庫執行個體與自訂資料庫參數群組相關聯。

## 主控台
<a name="Appendix.PostgreSQL.CommonDBATasks.pgaudit.basic-setup.CON"></a>

**設定 pgAudit 擴充功能**

1. 登入 AWS 管理主控台，開啟位於 [https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/) 的 Amazon RDS 主控台。

1. 在導覽窗格中，選擇您的 RDS for PostgreSQL 資料庫執行個體。

1. 針對您的 開啟 **Configuration** (組態) 索引標籤。RDS for PostgreSQL 資料庫執行個體。在執行個體詳細資訊之間，尋找 **Parameter group** (參數群組) 連結。

1. 選擇連結以開啟與 相關聯的自訂參數。RDS for PostgreSQL 資料庫執行個體。

1. 在 **Parameters** (參數) 搜尋欄位中，輸入 `shared_pre` 以尋找 `shared_preload_libraries` 參數。

1. 選擇 **Edit parameters** (編輯參數) 以存取屬性值。

1. 在 **Values** (值) 欄位中，將 `pgaudit` 新增至清單。使用逗號區隔值清單中的項目。  
![\[已新增 pgAudit 之 shared_preload_libaries 參數的影像。\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/images/apg_rpg_shared_preload_pgaudit.png)

1. 重新啟動 RDS for PostgreSQL 資料庫執行個體，以便您對 `shared_preload_libraries` 參數所做的變更生效。

1. 當執行個體可用時，請驗證 pgAudit 是否已初始化。使用 `psql` 連線至 RDS for PostgreSQL 資料庫執行個體，然後執行下列命令。

   ```
   SHOW shared_preload_libraries;
   shared_preload_libraries 
   --------------------------
   rdsutils,pgaudit
   (1 row)
   ```

1. 在初始化 pgAudit 之後，您現在可以建立擴充功能。您必須在初始化程式庫之後建立擴充功能，因為 `pgaudit` 擴充功能會安裝事件觸發條件，以稽核資料定義語言 (DDL) 陳述式。

   ```
   CREATE EXTENSION pgaudit;
   ```

1. 關閉 `psql` 工作階段。

   ```
   labdb=> \q
   ```

1. 登入 AWS 管理主控台，開啟位於 [https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/) 的 Amazon RDS 主控台。

1. 在清單中尋找 `pgaudit.log` 參數，並設定為適合您使用案例的適當值。例如，將 `pgaudit.log` 參數設定為 `write` (如下圖所示) 會擷取日誌的插入、更新、刪除，以及其他一些類型的變更。  
![\[pgaudit.log 參數與設定的影像。\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/images/rpg_set_pgaudit-log-level.png)

   您也可以針對 `pgaudit.log` 參數選擇下列其中一個值。
   + none – 這是預設值。不會記錄任何資料庫變更。
   + all – 記錄一切 (read、write、function、role、ddl、misc)。
   + ddl – 記錄未包含在 `ROLE` 類別中的所有資料定義語言 (DDL) 陳述式。
   + function – 記錄函數呼叫和 `DO` 區塊。
   + misc – 記錄其他命令，例如 `DISCARD`、`FETCH`、`CHECKPOINT`、`VACUUM` 和 `SET`。
   + read – 來源為關聯 (例如資料表) 或查詢時，記錄 `SELECT` 和 `COPY`。
   + role – 記錄與角色和權限相關的陳述式，例如 `GRANT`、`REVOKE`、`CREATE ROLE`、`ALTER ROLE` 和 `DROP ROLE`。
   + write – 目的地為關聯 (資料表) 時，記錄 `INSERT`、`UPDATE`、`DELETE`、`TRUNCATE` 和 `COPY`。

1. 選擇**儲存變更**。

1. 前往 [https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/)，開啟 Amazon RDS 主控台。

1. 在資料庫清單中，選擇您的 RDS for PostgreSQL 資料庫執行個體。

## AWS CLI
<a name="Appendix.PostgreSQL.CommonDBATasks.pgaudit.basic-setup.CLI"></a>

**設定 pgAudit**

若要使用 AWS CLI 設定 pgAudit，請呼叫 [modify-db-parameter-group](https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-parameter-group.html) 操作，來修改自訂參數群組中的稽核日誌參數，如下列程序所示。

1. 使用下列 AWS CLI 命令，將 `pgaudit` 新增至 `shared_preload_libraries` 參數。

   ```
   aws rds modify-db-parameter-group \
      --db-parameter-group-name custom-param-group-name \
      --parameters "ParameterName=shared_preload_libraries,ParameterValue=pgaudit,ApplyMethod=pending-reboot" \
      --region aws-region
   ```

1. 使用下列 AWS CLI 命令重新啟動 RDS for PostgreSQL 資料庫執行個體，以便初始化 pgaudit 程式庫。

   ```
   aws rds reboot-db-instance \
       --db-instance-identifier your-instance \
       --region aws-region
   ```

1. 當執行個體可用時，您可以驗證 `pgaudit` 是否已初始化。使用 `psql` 連線至 RDS for PostgreSQL 資料庫執行個體，然後執行下列命令。

   ```
   SHOW shared_preload_libraries;
   shared_preload_libraries 
   --------------------------
   rdsutils,pgaudit
   (1 row)
   ```

   在初始化 PgAudit 之後，您現在可以建立擴充功能。

   ```
   CREATE EXTENSION pgaudit;
   ```

1. 關閉 `psql` 工作階段，以便您可以使用 AWS CLI。

   ```
   labdb=> \q
   ```

1. 使用下列 AWS CLI 命令，來指定要由工作階段稽核記錄所記錄的陳述式類別。此範例會將 `pgaudit.log` 參數設定為 `write`，此參數會擷取日誌的插入、更新和刪除操作。

   ```
   aws rds modify-db-parameter-group \
      --db-parameter-group-name custom-param-group-name \
      --parameters "ParameterName=pgaudit.log,ParameterValue=write,ApplyMethod=pending-reboot" \
      --region aws-region
   ```

   您也可以針對 `pgaudit.log` 參數選擇下列其中一個值。
   + none – 這是預設值。不會記錄任何資料庫變更。
   + all – 記錄一切 (read、write、function、role、ddl、misc)。
   + ddl – 記錄未包含在 `ROLE` 類別中的所有資料定義語言 (DDL) 陳述式。
   + function – 記錄函數呼叫和 `DO` 區塊。
   + misc – 記錄其他命令，例如 `DISCARD`、`FETCH`、`CHECKPOINT`、`VACUUM` 和 `SET`。
   + read – 來源為關聯 (例如資料表) 或查詢時，記錄 `SELECT` 和 `COPY`。
   + role – 記錄與角色和權限相關的陳述式，例如 `GRANT`、`REVOKE`、`CREATE ROLE`、`ALTER ROLE` 和 `DROP ROLE`。
   + write – 目的地為關聯 (資料表) 時，記錄 `INSERT`、`UPDATE`、`DELETE`、`TRUNCATE` 和 `COPY`。

   使用下列 AWS CLI 命令，重新啟動 RDS for PostgreSQL 資料庫執行個體。

   ```
   aws rds reboot-db-instance \
       --db-instance-identifier your-instance \
       --region aws-region
   ```

# 稽核資料庫物件
<a name="Appendix.PostgreSQL.CommonDBATasks.pgaudit.auditing"></a>

在您的 RDS for PostgreSQL 資料庫執行個體上設定 pgAudit，並針對您的要求進行設定後，會在 PostgreSQL 日誌中擷取更詳細的資訊。例如，雖然預設 PostgreSQL 記錄組態會識別在資料庫資料表中進行變更的日期和時間，但使用 pgAudit 擴充功能時，日誌項目可以包括結構描述、進行變更的使用者，以及其他詳細資訊，視擴充功能參數的設定方式而定。您可以將稽核設定為以下列方式追蹤變更。
+ 對於每個工作階段，依使用者。對於工作階段層級，您可以擷取完整的命令文字。
+ 對於每個物件，依使用者和資料庫。

在系統上建立 `rds_pgaudit` 角色，然後將此角色新增至自訂參數群組中的 `pgaudit.role` 參數時，便會啟用物件稽核功能。根據預設，未設定 `pgaudit.role` 參數，且唯一允許的值為 `rds_pgaudit`。下列步驟假設 `pgaudit` 已初始化，且您已遵循[設定 pgAudit 擴充功能](Appendix.PostgreSQL.CommonDBATasks.pgaudit.basic-setup.md)中的程序建立 `pgaudit` 擴充功能。

![\[設定 pgAudit 後 PostgreSQL 日誌檔的影像。\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/images/pgaudit-log-example.png)


如此範例所示，「LOG: AUDIT: SESSION」一行提供資料表及其結構描述的相關資訊，以及其他詳細資訊。

**設定物件稽核**

1. 使用 `psql` 連線至 RDS for PostgreSQL 資料庫執行個體。。

   ```
   psql --host=your-instance-name.aws-region.rds.amazonaws.com --port=5432 --username=postgrespostgres --password --dbname=labdb
   ```

1. 使用下列命令建立名為 `rds_pgaudit` 的資料庫角色。

   ```
   labdb=> CREATE ROLE rds_pgaudit;
   CREATE ROLE
   labdb=>
   ```

1. 關閉 `psql` 工作階段。

   ```
   labdb=> \q
   ```

   在接下來的幾個步驟中，使用 AWS CLI 修改自訂參數群組中的稽核日誌參數。

1. 使用下列 AWS CLI 命令，將 `pgaudit.role` 參數設定為 `rds_pgaudit`。根據預設，此參數是空的，且 `rds_pgaudit` 是唯一允許的值。

   ```
   aws rds modify-db-parameter-group \
      --db-parameter-group-name custom-param-group-name \
      --parameters "ParameterName=pgaudit.role,ParameterValue=rds_pgaudit,ApplyMethod=pending-reboot" \
      --region aws-region
   ```

1. 使用下列 AWS CLI 命令，重新啟動 RDS for PostgreSQL 資料庫執行個體，以便您對參數所做的變更生效。

   ```
   aws rds reboot-db-instance \
       --db-instance-identifier your-instance \
       --region aws-region
   ```

1. 執行下列命令來確認 `pgaudit.role` 已設定為 `rds_pgaudit`。

   ```
   SHOW pgaudit.role;
   pgaudit.role 
   ------------------
   rds_pgaudit
   ```

如要測試 pgAudit 記錄功能，您可以執行幾個要稽核的範例命令。例如，您可以執行下列命令。

```
CREATE TABLE t1 (id int);
GRANT SELECT ON t1 TO rds_pgaudit;
SELECT * FROM t1;
id 
----
(0 rows)
```

資料庫記錄應包含類似以下的項目。

```
...
2017-06-12 19:09:49 UTC:...:rds_test@postgres:[11701]:LOG: AUDIT:
OBJECT,1,1,READ,SELECT,TABLE,public.t1,select * from t1;
...
```

如需有關檢視日誌的資訊，請參閱 [監控 Amazon RDS 日誌檔案](USER_LogAccess.md)。

若要進一步了解 pgAudit 擴充功能，請參閱 GitHub 上的 [pgAudit](https://github.com/pgaudit/pgaudit/blob/master/README.md)。

# 從稽核記錄中排除使用者或資料庫
<a name="Appendix.PostgreSQL.CommonDBATasks.pgaudit.exclude-user-db"></a>

如[ RDS for PostgreSQL 資料庫日誌檔案](USER_LogAccess.Concepts.PostgreSQL.md)中所述，PostgreSQL 日誌會取用儲存空間。使用 pgAudit 擴充功能會在不同程度上增加日誌中收集的資料量，取決於您追蹤的變更。您可能不需要稽核 中的每個使用者或資料庫。RDS for PostgreSQL 資料庫執行個體。

若要將對儲存的影響降到最低，並避免不必要地擷取稽核記錄，您可以將使用者和資料庫排除在稽核之外。您也可以在給定的工作階段中變更記錄。下列範例向您展示做法。

**注意**  
優先處理工作階段層級的參數設定，再處理 RDS for PostgreSQL 資料庫執行個體中的設定。如果您不想要資料庫使用者略過稽核記錄組態設定，請務必變更其許可。

假設您的 RDS for PostgreSQL 資料庫執行個體已設定為稽核所有使用者和資料庫的相同層級活動。然後，您決定不想要稽核使用者 `myuser`。您可以使用下列 SQL 命令來關閉 `myuser` 的稽核。

```
ALTER USER myuser SET pgaudit.log TO 'NONE';
```

然後，您可以使用下列查詢來檢查 `pgaudit.log` 的 `user_specific_settings` 欄，以確認參數已設定為 `NONE`。

```
SELECT
    usename AS user_name,
    useconfig AS user_specific_settings
FROM
    pg_user
WHERE
    usename = 'myuser';
```

您會看到如下輸出。

```
 user_name | user_specific_settings
-----------+------------------------
 myuser    | {pgaudit.log=NONE}
(1 row)
```

您可以使用下列命令，在資料庫的工作階段當中關閉特定使用者的記錄。

```
ALTER USER myuser IN DATABASE mydatabase SET pgaudit.log TO 'none';
```

使用下列查詢，針對特定使用者和資料庫組合檢查 pgaudit.log 的 settings 欄。

```
SELECT
    usename AS "user_name",
    datname AS "database_name",
    pg_catalog.array_to_string(setconfig, E'\n') AS "settings"
FROM
    pg_catalog.pg_db_role_setting s
    LEFT JOIN pg_catalog.pg_database d ON d.oid = setdatabase
    LEFT JOIN pg_catalog.pg_user r ON r.usesysid = setrole
WHERE
    usename = 'myuser'
    AND datname = 'mydatabase'
ORDER BY
    1,
    2;
```

您會看到類似下列的輸出。

```
  user_name | database_name |     settings
-----------+---------------+------------------
 myuser    | mydatabase    | pgaudit.log=none
(1 row)
```

在關閉 `myuser` 的稽核之後，您決定不想要追蹤 `mydatabase` 的變更。您可以使用下列命令來關閉該特定資料庫的稽核。

```
ALTER DATABASE mydatabase SET pgaudit.log to 'NONE';
```

然後，使用下列查詢來檢查 database\$1specific\$1settings 欄，以確認 pgaudit.log 已設定為 NONE。

```
SELECT
a.datname AS database_name,
b.setconfig AS database_specific_settings
FROM
pg_database a
FULL JOIN pg_db_role_setting b ON a.oid = b.setdatabase
WHERE
a.datname = 'mydatabase';
```

您會看到如下輸出。

```
 database_name | database_specific_settings
---------------+----------------------------
 mydatabase    | {pgaudit.log=NONE}
(1 row)
```

若要將設定回復為 myuser 的預設設定，請使用下列命令：

```
ALTER USER myuser RESET pgaudit.log;
```

若要將設定回復為資料庫的預設設定，請使用下列命令。

```
ALTER DATABASE mydatabase RESET pgaudit.log;
```

若要將使用者和資料庫重設為預設設定，請使用下列命令。

```
ALTER USER myuser IN DATABASE mydatabase RESET pgaudit.log;
```

您也可以將 `pgaudit.log` 設定為 `pgaudit.log` 參數的其他允許值之一，將特定事件擷取至日誌。如需更多詳細資訊，請參閱 [允許的 `pgaudit.log` 參數設定清單](Appendix.PostgreSQL.CommonDBATasks.pgaudit.reference.md#Appendix.PostgreSQL.CommonDBATasks.pgaudit.reference.pgaudit-log-settings)。

```
ALTER USER myuser SET pgaudit.log TO 'read';
ALTER DATABASE mydatabase SET pgaudit.log TO 'function';
ALTER USER myuser IN DATABASE mydatabase SET pgaudit.log TO 'read,function'
```

# pgAudit 擴充功能的參考
<a name="Appendix.PostgreSQL.CommonDBATasks.pgaudit.reference"></a>

您可以變更本節中列出的一或多個參數，針對稽核日誌指定您所需的詳細資訊層級。

## 控制 pgAudit 行為
<a name="Appendix.PostgreSQL.CommonDBATasks.pgaudit.reference.basic-setup.parameters"></a>

您可以變更下表中列出的一或多個參數來控制稽核記錄。


| 參數 | Description | 
| --- | --- | 
| `pgaudit.log`  | 指定工作階段稽核記錄將記錄哪些陳述式類別。允許的值包括 ddl、function、misc、read、role、write、none、all。如需詳細資訊，請參閱[允許的 `pgaudit.log` 參數設定清單](#Appendix.PostgreSQL.CommonDBATasks.pgaudit.reference.pgaudit-log-settings)。 | 
| `pgaudit.log_catalog` | 開啟 (設定為 1) 時，如果陳述式中的所有關聯都在 pg\$1catalog 中，則會將陳述式新增至稽核線索。 | 
| `pgaudit.log_level` | 指定要用於日誌項目的日誌層級。允許的值：disabled、debug5、debug4、debug3、debug2、debug1、info、notice、warning、log | 
| `pgaudit.log_parameter` | 開啟 (設定為 1) 時，會在稽核日誌中擷取隨陳述式傳遞的參數。 | 
| `pgaudit.log_relation` | 開啟 (設定為 1) 時，工作階段的稽核日誌會為 SELECT 或 DML 陳述式中參考的每個關聯 (TABLE、VIEW 等) 建立個別的日誌項目。 | 
| `pgaudit.log_statement_once` | 指定日誌記錄包含的陳述式文字和參數，具有陳述式/子陳述式組合的第一個日誌項目，還是具有每個項目。 | 
| `pgaudit.role` | 指定用於物件稽核日誌記錄的主要角色。唯一允許的項目為 `rds_pgaudit`。 | 

## 允許的 `pgaudit.log` 參數設定清單
<a name="Appendix.PostgreSQL.CommonDBATasks.pgaudit.reference.pgaudit-log-settings"></a>

 


| Value | Description | 
| --- | --- | 
| 無 | 這是預設值。不會記錄任何資料庫變更。 | 
| 全部 | 記錄一切 (read、write、function、role、ddl、misc)。 | 
| ddl | 記錄未包含在 `ROLE` 類別中的所有資料定義語言 (DDL) 陳述式。 | 
| 函數 | 記錄函數呼叫和 `DO` 區塊。 | 
| misc | 記錄其他命令，例如 `DISCARD`、`FETCH`、`CHECKPOINT`、`VACUUM` 和 `SET`。 | 
| 讀取 | 來源為關聯 (例如資料表) 或查詢時，記錄 `SELECT` 和 `COPY`。 | 
| role | 記錄與角色和權限相關的陳述式，例如 `GRANT`、`REVOKE`、`CREATE ROLE`、`ALTER ROLE` 和 `DROP ROLE`。 | 
| write | 目的地為關聯 (資料表) 時，記錄 `INSERT`、`UPDATE`、`DELETE`、`TRUNCATE` 和 `COPY`。 | 

若要使用工作階段稽核功能記錄多個事件類型，請使用逗號分隔清單。若要記錄所有事件類型，請將 `pgaudit.log` 設定為 `ALL`。重新啟動資料庫執行個體以套用變更。

您可以透過物件稽核，調整稽核記錄以使用特定關聯。例如，您可以指定您想要針對一或多個資料表上的 `READ` 操作稽核記錄。

# 使用 PostgreSQL pg\$1cron 擴充功能排程維護
<a name="PostgreSQL_pg_cron"></a>

您可以使用 PostgreSQL `pg_cron` 擴充功能，來排程 PostgreSQL 資料庫內的維護命令。如需擴充功能的詳細資訊，請參閱 pg\$1cron 文件中的[什麼是 pg\$1cron？](https://github.com/citusdata/pg_cron)。

RDS for PostgreSQL 引擎 12.5 版及更新版本支援 `pg_cron` 擴充功能。

若要深入了解如何使用 `pg_cron`，請參閱[在 RDS for PostgreSQL 或 Aurora PostgreSQL 相容版本資料庫上使用 pg\$1cron 排程任務](https://aws.amazon.com/blogs/database/schedule-jobs-with-pg_cron-on-your-amazon-rds-for-postgresql-or-amazon-aurora-for-postgresql-databases/)

**注意**  
`pg_cron` 延伸版本會在 pg\$1available\$1extensions 檢視中顯示為兩個數字的版本，例如 1.6。雖然在某些內容中可能會看到三個數字的版本，例如 1.6.4 或 1.6.5，但您必須在執行延伸升級時指定兩個數字的版本。

**Topics**
+ [設定 pg\$1cron 擴充功能](#PostgreSQL_pg_cron.enable)
+ [授與資料車使用者使用 pg\$1cron 的許可](#PostgreSQL_pg_cron.permissions)
+ [排定 pg\$1cron 任務](#PostgreSQL_pg_cron.examples)
+ [pg\$1cron 擴充功能的參考](#PostgreSQL_pg_cron.reference)

## 設定 pg\$1cron 擴充功能
<a name="PostgreSQL_pg_cron.enable"></a>

設定 `pg_cron` 擴充功能，如下所示：

1. 修改與 PostgreSQL 資料庫執行個體關聯的自訂參數群組，並將 `pg_cron` 新增至 `shared_preload_libraries` 參數值。
   + 如果 RDS for PostgreSQL 資料庫執行個體使用 `rds.allowed_extensions` 參數顯式列可以安裝的擴展名清單，您需要將 `pg_cron` 擴展功能新增至清單。只有特定版本的 RDS for PostgreSQL 支援 `rds.allowed_extensions` 參數。根據預設，允許所有可用的擴充功能。如需詳細資訊，請參閱[限制安裝 PostgreSQL 擴充功能](PostgreSQL.Concepts.General.FeatureSupport.Extensions.md#PostgreSQL.Concepts.General.FeatureSupport.Extensions.Restriction)。

   重新啟動 PostgreSQL 資料庫執行個體，使參數群組的變更生效。若要深入了解如何使用參數群組，請參閱 [修改 Amazon RDS 中的資料庫參數群組中的參數](USER_WorkingWithParamGroups.Modifying.md)。 

1. 重新啟動 PostgreSQL 資料庫執行個體之後，請使用具有 `rds_superuser` 許可的帳戶執行下列命令。例如，如果您在為 RDS for PostgreSQL 資料庫執行個體建立 RDS 時使用了預設設定，請以使用者 `postgres` 身分連接並建立擴充功能。

   ```
   CREATE EXTENSION pg_cron;
   ```

   `pg_cron` 排程器設定於名為 `postgres` 的預設 PostgreSQL 資料庫內。`pg_cron` 物件會在此 `postgres` 資料庫中建立，而且所有排程動作都會在此資料庫中執行。

1. 您可以使用預設設定，或將任務排程在 PostgreSQL 資料庫執行個體的其他資料庫中執行。若要將任務排程至 PostgreSQL 資料庫執行個體中的其他資料庫，請參閱 [為預設資料庫以外的資料庫排程 cron 任務](#PostgreSQL_pg_cron.otherDB) 中的範例。

## 授與資料車使用者使用 pg\$1cron 的許可
<a name="PostgreSQL_pg_cron.permissions"></a>

安裝 `pg_cron` 擴充功能需要 `rds_superuser` 權限。然而，使用 `pg_cron` 的許可能夠授予 (由 `rds_superuser` 群組/角色的成員) 其他資料庫使用者，讓他們可以安排自己的任務。建議您只有在能改善生產環境中的作業時，才視需要授予對 `cron` 結構描述的許可。

若要授予資料庫使用者對 `cron` 結構描述的許可，請執行以下命令：

```
postgres=> GRANT USAGE ON SCHEMA cron TO db-user;
```

這樣會給予 *db-user* 存取 `cron` 結構描述的許可，以針對它們有權存取的物件排程 cron 作業。如果資料庫使用者沒有許可，則作業會在將錯誤訊息發佈至 `postgresql.log` 檔案後失敗，如下所示：

```
2020-12-08 16:41:00 UTC::@:[30647]:ERROR: permission denied for table table-name
2020-12-08 16:41:00 UTC::@:[27071]:LOG: background worker "pg_cron" (PID 30647) exited with exit code 1
```

換句話說，請確保被授予 `cron` 結構描述許可的資料庫使用者也具有計劃排程之物件 (資料表、結構描述等) 的許可。

Cron 作業及其成功或失敗的詳細資訊也會擷取於 `cron.job_run_details` 資料表。如需詳細資訊，請參閱[用於排程工作和擷取狀態的資料表](#PostgreSQL_pg_cron.tables)。

## 排定 pg\$1cron 任務
<a name="PostgreSQL_pg_cron.examples"></a>

以下各節示範如何使用 `pg_cron` 任務排程各種管理任務。

**注意**  
建立 `pg_cron` 工作時，請檢查 `max_worker_processes` 設定大於數目 `cron.max_running_jobs`。如果 `pg_cron` 任務耗盡背景工作者程序，則會失敗。`pg_cron` 任務的預設數字為 `5`。如需詳細資訊，請參閱[用於管理 pg\$1cron 擴充功能的參數](#PostgreSQL_pg_cron.parameters)。

**Topics**
+ [正在清理資料表](#PostgreSQL_pg_cron.vacuum)
+ [正在清除 pg\$1cron 歷史記錄資料表](#PostgreSQL_pg_cron.job_run_details)
+ [僅將錯誤記錄到 postgresql.log 檔案](#PostgreSQL_pg_cron.log_run)
+ [為預設資料庫以外的資料庫排程 cron 任務](#PostgreSQL_pg_cron.otherDB)

### 正在清理資料表
<a name="PostgreSQL_pg_cron.vacuum"></a>

自動資料清理功能可處理大多數情況下的清理維護。但是，您可能想要在您選定的時間來排定清理特定的資料表。

另請參閱 [在 Amazon RDS for PostgreSQL 上使用 PostgreSQL 自動清空](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.md)。

以下為使用 `cron.schedule` 函數來設定一個任務，以在每天 22:00 (GMT) 於特定資料表上使用 `VACUUM FREEZE` 的範例。

```
SELECT cron.schedule('manual vacuum', '0 22 * * *', 'VACUUM FREEZE pgbench_accounts');
 schedule
----------
1
(1 row)
```

執行上述範例之後，您可以如下所示檢查 `cron.job_run_details` 資料表中的歷史記錄。

```
postgres=> SELECT * FROM cron.job_run_details;
jobid  | runid | job_pid | database | username | command                        | status    | return_message | start_time                    | end_time
-------+-------+---------+----------+----------+--------------------------------+-----------+----------------+-------------------------------+-------------------------------
 1     | 1     | 3395    | postgres | adminuser| vacuum freeze pgbench_accounts | succeeded | VACUUM         | 2020-12-04 21:10:00.050386+00 | 2020-12-04 21:10:00.072028+00
(1 row)
```

以下是查詢 `cron.job_run_details` 資料表以查看失敗的任務。

```
postgres=> SELECT * FROM cron.job_run_details WHERE status = 'failed';
jobid | runid | job_pid | database | username | command                       | status | return_message                                   | start_time                    | end_time
------+-------+---------+----------+----------+-------------------------------+--------+--------------------------------------------------+-------------------------------+------------------------------
 5    | 4     | 30339   | postgres | adminuser| vacuum freeze pgbench_account | failed | ERROR: relation "pgbench_account" does not exist | 2020-12-04 21:48:00.015145+00 | 2020-12-04 21:48:00.029567+00
(1 row)
```

如需詳細資訊，請參閱[用於排程工作和擷取狀態的資料表](#PostgreSQL_pg_cron.tables)。

### 正在清除 pg\$1cron 歷史記錄資料表
<a name="PostgreSQL_pg_cron.job_run_details"></a>

`cron.job_run_details` 資料表包含 cron 任務的歷史記錄，它可能會隨著時間的推移而變得非常大。建議您排程清除此資料表的任務。例如，保留一週的項目可能足以進行疑難排解。

下列範例會使用 [cron.schedule](#PostgreSQL_pg_cron.schedule) 函數來排程每天在午夜執行的任務，以清除 `cron.job_run_details` 資料表。這項任務只保留過去七天。如下所示使用您的 `rds_superuser` 帳戶來排程任務。

```
SELECT cron.schedule('0 0 * * *', $$DELETE 
    FROM cron.job_run_details 
    WHERE end_time < now() - interval '7 days'$$);
```

如需詳細資訊，請參閱[用於排程工作和擷取狀態的資料表](#PostgreSQL_pg_cron.tables)。

### 僅將錯誤記錄到 postgresql.log 檔案
<a name="PostgreSQL_pg_cron.log_run"></a>

若要防止寫入至 `cron.job_run_details` 資料表，請修改與 PostgreSQL 資料庫執行個體關聯的參數群組，並將 `cron.log_run` 參數設定為關閉。`pg_cron` 延伸模組不再寫入至資料表，而且只會將錯誤擷取至 `postgresql.log` 檔案。如需詳細資訊，請參閱[修改 Amazon RDS 中的資料庫參數群組中的參數](USER_WorkingWithParamGroups.Modifying.md)。

使用下列命令來檢查 `cron.log_run` 參數的值。

```
postgres=> SHOW cron.log_run;
```

如需詳細資訊，請參閱[用於管理 pg\$1cron 擴充功能的參數](#PostgreSQL_pg_cron.parameters)。

### 為預設資料庫以外的資料庫排程 cron 任務
<a name="PostgreSQL_pg_cron.otherDB"></a>

`pg_cron` 的中繼資料都保留在名為 `postgres` 的 PostgreSQL 預設資料庫中。由於使用背景工作者來執行維護 cron 任務，因此您可以在 PostgreSQL 資料庫執行個體內的任何資料庫中排程任務︰

**注意**  
只有具有 `rds_superuser` 角色或 `rds_superuser` 權限的使用者才能列出資料庫中的所有 Cron 任務。其他使用者在 `cron.job` 資料表中只能檢視自己的任務。

1. 在 cron 資料庫中，使用 [cron.schedule](#PostgreSQL_pg_cron.schedule) 如常排程任務。

   ```
   postgres=> SELECT cron.schedule('database1 manual vacuum', '29 03 * * *', 'vacuum freeze test_table');
   ```

1. 作為使用 `rds_superuser` 角色的使用者，請為您剛建立的任務更新資料庫欄，以便在 PostgreSQL 資料庫執行個體內的另一個資料庫中執行。

   ```
   postgres=> UPDATE cron.job SET database = 'database1' WHERE jobid = 106;
   ```

1.  透過查詢 `cron.job` 資料表進行驗證。

   ```
   postgres=> SELECT * FROM cron.job;
   jobid | schedule    | command                        | nodename  | nodeport | database | username  | active | jobname
   ------+-------------+--------------------------------+-----------+----------+----------+-----------+--------+-------------------------
   106   | 29 03 * * * | vacuum freeze test_table       | localhost | 8192     | database1| adminuser | t      | database1 manual vacuum
     1   | 59 23 * * * | vacuum freeze pgbench_accounts | localhost | 8192     | postgres | adminuser | t      | manual vacuum
   (2 rows)
   ```

**注意**  
在某些情況下，您可能會新增一個打算在其他資料庫上執行的 cron 任務。在此情況下，任務可能會嘗試在預設資料庫 (`postgres`) 中執行，然後再更新正確的資料庫資料欄。如果使用者名稱具有許可，則任務會在預設資料庫中成功執行。

## pg\$1cron 擴充功能的參考
<a name="PostgreSQL_pg_cron.reference"></a>

您可以使用下列參數、函數和資料表搭配 `pg_cron` 擴充功能。如需詳細資訊，請參閱 pg\$1cron 文件中的[什麼是 pg\$1cron？](https://github.com/citusdata/pg_cron)。

**Topics**
+ [用於管理 pg\$1cron 擴充功能的參數](#PostgreSQL_pg_cron.parameters)
+ [函數參考：cron.schedule](#PostgreSQL_pg_cron.schedule)
+ [函數參考：cron.unschedule](#PostgreSQL_pg_cron.unschedule)
+ [用於排程工作和擷取狀態的資料表](#PostgreSQL_pg_cron.tables)

### 用於管理 pg\$1cron 擴充功能的參數
<a name="PostgreSQL_pg_cron.parameters"></a>

以下是用來控制 `pg_cron` 擴充功能行為的參數清單。


| 參數 | Description | 
| --- | --- | 
| cron.database\$1name |  在其中保留 `pg_cron` 中繼資料的資料庫。  | 
| cron.host |  要連線至 PostgreSQL 的主機名稱。您無法修改此值。  | 
| cron.log\$1run |  記錄 `job_run_details` 資料表執行的每個任務。值為 `on` 或 `off`。如需詳細資訊，請參閱 [用於排程工作和擷取狀態的資料表](#PostgreSQL_pg_cron.tables)。  | 
| cron.log\$1statement |  在執行之前記錄所有 cron 陳述式。值為 `on` 或 `off`。  | 
| cron.max\$1running\$1jobs |  可同時執行的任務數量上限。  | 
| cron.use\$1background\$1workers |  使用背景工作者而不是用戶端工作階段。您無法修改此值。  | 

使用下列 SQL 命令來顯示這些參數及其值。

```
postgres=> SELECT name, setting, short_desc FROM pg_settings WHERE name LIKE 'cron.%' ORDER BY name;
```

### 函數參考：cron.schedule
<a name="PostgreSQL_pg_cron.schedule"></a>

這個函數會排程一個 cron 任務。任務最初是在預設 `postgres` 資料庫中進行排程。該函數會返回表示任務識別符的 `bigint` 值。若要將任務排程在 PostgreSQL 資料庫執行個體中的其他資料庫中執行，請參閱 [為預設資料庫以外的資料庫排程 cron 任務](#PostgreSQL_pg_cron.otherDB) 中的範例。

該函數有兩種語法格式。

**語法**  

```
cron.schedule (job_name,
    schedule,
    command
);

cron.schedule (schedule,
    command
);
```

**參數**      
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/PostgreSQL_pg_cron.html)

**範例**  

```
postgres=> SELECT cron.schedule ('test','0 10 * * *', 'VACUUM pgbench_history');
 schedule
----------
      145
(1 row)

postgres=> SELECT cron.schedule ('0 15 * * *', 'VACUUM pgbench_accounts');
 schedule
----------
      146
(1 row)
```

### 函數參考：cron.unschedule
<a name="PostgreSQL_pg_cron.unschedule"></a>

這個函數會刪除 cron 任務。您可以指定 `job_name` 或 `job_id`，兩者之一。政策可確保您是移除任務排程的擁有者。該函數會返回一個表示成功或失敗的布林值。

此函數的語法格示如下。

**語法**  

```
cron.unschedule (job_id);

cron.unschedule (job_name);
```

**參數**      
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/PostgreSQL_pg_cron.html)

**範例**  

```
postgres=> SELECT cron.unschedule(108);
 unschedule
------------
 t
(1 row)

postgres=> SELECT cron.unschedule('test');
 unschedule
------------
 t
(1 row)
```

### 用於排程工作和擷取狀態的資料表
<a name="PostgreSQL_pg_cron.tables"></a>

下表用於排程 cron 任務以及記錄任務完成的方式。


| 表格 | 描述 | 
| --- | --- | 
| cron.job |  包含每個排程任務的中繼資料。大部分與此資料表的互動應透過使用 `cron.schedule` 和 `cron.unschedule` 函數來完成。  我們建議您不要將更新或插入權限直接提供給此資料表。這樣做將允許使用者更新 `username` 資料欄，以 `rds-superuser` 身分執行任務。   | 
| cron.job\$1run\$1details |  包含過去排程任務執行的歷史記錄資訊。這對於調查任務執行的狀態、傳回訊息以及開始和結束時間非常有用。  若要防止此資料表無限期增長，請定期清除。如需範例，請參閱 [正在清除 pg\$1cron 歷史記錄資料表](#PostgreSQL_pg_cron.job_run_details)。   | 

# 使用 pglogical 跨執行個體同步資料
<a name="Appendix.PostgreSQL.CommonDBATasks.pglogical"></a>

所有目前可用的 RDS for PostgreSQL 版本都支援 `pglogical` 延伸模組。pglogical 延伸模組早於 PostgreSQL 在第 10 版中引入的功能，其類似於邏輯複寫功能。如需詳細資訊，請參閱 [為 Amazon RDS for PostgreSQL 執行邏輯複寫](PostgreSQL.Concepts.General.FeatureSupport.LogicalReplication.md)。

`pglogical` 延伸模組支援在兩個或以上 之間進行邏輯複寫。RDS for PostgreSQL 資料庫執行個體。它也支援在不同的 PostgreSQL 版本之間，以及在 RDS for PostgreSQL 資料庫執行個體和 Aurora PostgreSQL 資料庫叢集上執行的資料庫之間進行複寫。`pglogical` 延伸模組會使用發佈-訂閱模型，將資料表和其他物件 (例如序列) 的變更從發佈者複製到訂閱者。它依賴複寫槽，以確保變更從發佈者節點同步到訂閱者節點，其定義如下。
+ *發佈者節點*是 RDS for PostgreSQL 資料庫執行個體，其是要複寫到其他節點的資料來源。發佈者節點定義要在發佈集中複製的資料表。
+ *訂閱者節點*是 RDS for PostgreSQL 資料庫執行個體，其會從發佈者接收 WAL 更新。訂閱者會建立訂閱以連線至發佈者，並取得解碼的 WAL 資料。訂閱者建立訂閱時，系統會在發佈者節點上建立複寫槽。

您可以在以下內容中找到如何設定 `pglogical` 延伸模組的相關資訊。

**Topics**
+ [pglogical 延伸模組的需求和限制](#Appendix.PostgreSQL.CommonDBATasks.pglogical.requirements-limitations)
+ [設定 pglogical 延伸模組](Appendix.PostgreSQL.CommonDBATasks.pglogical.basic-setup.md)
+ [針對 RDS for PostgreSQL 資料庫執行個體設定邏輯複寫](Appendix.PostgreSQL.CommonDBATasks.pglogical.setup-replication.md)
+ [在重大升級之後重新建立邏輯複寫](Appendix.PostgreSQL.CommonDBATasks.pglogical.recover-replication-after-upgrade.md)
+ [管理 RDS for PostgreSQL 的邏輯複寫槽](Appendix.PostgreSQL.CommonDBATasks.pglogical.handle-slots.md)
+ [pglogical 延伸模組的參數參考](Appendix.PostgreSQL.CommonDBATasks.pglogical.reference.md)

## pglogical 延伸模組的需求和限制
<a name="Appendix.PostgreSQL.CommonDBATasks.pglogical.requirements-limitations"></a>

所有目前可用的 RDS for PostgreSQL 版本都支援 `pglogical` 延伸模組。

發佈者節點和訂閱者節點都必須針對邏輯複寫進行設定。

您想要從發佈者複寫到訂閱者的資料表必須具有相同的名稱和相同的結構描述。這些資料表亦須包含相同的資料欄，而且這些資料欄必須使用相同的資料類型。發佈者和訂閱者資料表都必須具有相同的主索引鍵。建議您僅使用 PRIMARY KEY 作為唯一限制條件。

對於 CHECK 限制條件和 NOT NULL 限制條件，訂閱者節點上的資料表與發佈者節點上的資料表相比之下，可以具有更寬鬆的限制條件。

`pglogical` 延伸模組會提供 PostgreSQL (第 10 版及更新版本) 內建邏輯複寫功能不支援的功能，例如雙向複寫。如需詳細資訊，請參閱[使用 pglogical 進行 PostgreSQL 雙向複寫](https://aws.amazon.com/blogs/database/postgresql-bi-directional-replication-using-pglogical/)。

# 設定 pglogical 延伸模組
<a name="Appendix.PostgreSQL.CommonDBATasks.pglogical.basic-setup"></a>

若要在 RDS for PostgreSQL 資料庫執行個體上設定 `pglogical` 延伸模組，請將 `pglogical` 新增至下列群組上的共用程式庫：RDS for PostgreSQL 資料庫執行個體的自訂資料庫參數群組。您亦需將 `rds.logical_replication` 參數的值設為 `1`，以開啟邏輯解碼。最後，您可以在資料庫中建立延伸模組。您可以使用 AWS 管理主控台 或 AWS CLI 進行這些任務。

您必須具有做為 `rds_superuser` 角色的許可，才能執行這些任務。

以下步驟假設您的 RDS for PostgreSQL 資料庫執行個體與自訂資料庫參數群組相關聯。如需建立自訂資料庫叢集參數群組的相關資訊，請參閱 [Amazon RDS 的參數群組](USER_WorkingWithParamGroups.md)。

## 主控台
<a name="Appendix.PostgreSQL.CommonDBATasks.pglogical.basic-setup.CON"></a>

**設定 pglogical 延伸模組**

1. 登入 AWS 管理主控台 ，並在 [https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/)：// 開啟 Amazon RDS 主控台。

1. 在導覽窗格中，選擇您的 RDS for PostgreSQL 資料庫執行個體。

1. 針對您的 開啟 **Configuration** (組態) 索引標籤。RDS for PostgreSQL 資料庫執行個體。在執行個體詳細資訊之間，尋找 **Parameter group** (參數群組) 連結。

1. 選擇連結以開啟與 相關聯的自訂參數。RDS for PostgreSQL 資料庫執行個體。

1. 在 **Parameters** (參數) 搜尋欄位中，輸入 `shared_pre` 以尋找 `shared_preload_libraries` 參數。

1. 選擇 **Edit parameters** (編輯參數) 以存取屬性值。

1. 在 **Values** (值) 欄位中，將 `pglogical` 新增至清單。使用逗號區隔值清單中的項目。  
![\[已新增 pglogical 之 shared_preload_libraries 參數的影像。\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/images/apg_rpg_shared_preload_pglogical.png)

1. 尋找 `rds.logical_replication` 參數並將其設為 `1`，以開啟邏輯複寫。

1. 重新啟動 RDS for PostgreSQL 資料庫執行個體，讓您的變更生效。

1. 當執行個體可用時，您可以使用 `psql` (或 pgAdmin) 連線至 RDS for PostgreSQL 資料庫執行個體。。

   ```
   psql --host=111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password --dbname=labdb
   ```

1. 若要驗證 pglogical 是否已初始化，請執行下列命令。

   ```
   SHOW shared_preload_libraries;
   shared_preload_libraries 
   --------------------------
   rdsutils,pglogical
   (1 row)
   ```

1. 驗證啟用邏輯解碼的設定，如下所示。

   ```
   SHOW wal_level;
   wal_level
   -----------
    logical
   (1 row)
   ```

1. 建立延伸模組，如下所示。

   ```
   CREATE EXTENSION pglogical;
   EXTENSION CREATED
   ```

1. 選擇**儲存變更**。

1. 前往 [https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/)，開啟 Amazon RDS 主控台。

1. 從資料庫清單中選擇 RDS for PostgreSQL 資料庫執行個體以選取它，然後從 Actions (動作) 功能表中選擇 **Reboot** (重新啟動)。

## AWS CLI
<a name="Appendix.PostgreSQL.CommonDBATasks.pglogical.basic-setup.CLI"></a>

**設定 pglogical 延伸模組**

若要使用 設定 pglogical AWS CLI，您可以呼叫 [modify-db-parameter-group](https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-parameter-group.html) 操作來修改自訂參數群組中的特定參數，如下列程序所示。

1. 使用下列 AWS CLI 命令將 `pglogical`新增至 `shared_preload_libraries` 參數。

   ```
   aws rds modify-db-parameter-group \
      --db-parameter-group-name custom-param-group-name \
      --parameters "ParameterName=shared_preload_libraries,ParameterValue=pglogical,ApplyMethod=pending-reboot" \
      --region aws-region
   ```

1. 使用下列 AWS CLI 命令將 `rds.logical_replication` 設定為 `1`，以開啟 RDS for PostgreSQL 資料庫執行個體。

   ```
   aws rds modify-db-parameter-group \
      --db-parameter-group-name custom-param-group-name \
      --parameters "ParameterName=rds.logical_replication,ParameterValue=1,ApplyMethod=pending-reboot" \
      --region aws-region
   ```

1. 使用以下 AWS CLI 命令重新啟動 RDS for PostgreSQL 資料庫執行個體，以便初始化 pglogical 程式庫。

   ```
   aws rds reboot-db-instance \
       --db-instance-identifier your-instance \
       --region aws-region
   ```

1. 當執行個體可用時，請使用 `psql` 連線至 RDS for PostgreSQL 資料庫執行個體。。

   ```
   psql --host=111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password --dbname=labdb
   ```

1. 建立延伸模組，如下所示。

   ```
   CREATE EXTENSION pglogical;
   EXTENSION CREATED
   ```

1. 使用以下 AWS CLI 命令重新啟動 RDS for PostgreSQL 資料庫執行個體。

   ```
   aws rds reboot-db-instance \
       --db-instance-identifier your-instance \
       --region aws-region
   ```

# 針對 RDS for PostgreSQL 資料庫執行個體設定邏輯複寫
<a name="Appendix.PostgreSQL.CommonDBATasks.pglogical.setup-replication"></a>

下列程序說明如何在兩個 RDS for PostgreSQL 資料庫執行個體之間啟動邏輯複寫。這些步驟假設來源 (發佈者) 和目標 (訂閱者) 都已設定 `pglogical` 延伸模組，如 [設定 pglogical 延伸模組](Appendix.PostgreSQL.CommonDBATasks.pglogical.basic-setup.md) 中所述。

**注意**  
訂閱者節點的 `node_name` 不能以 `rds` 開頭。

**建立發佈者節點並定義要複製的資料表**

這些步驟假設您的 RDS for PostgreSQL 資料庫執行個體具有一個資料庫，其中包含一或多個您要複寫到另一個節點的資料表。您必須在訂閱者上重新建立來自發佈者的資料表結構，因此必要時先取得資料表結構。您可以使用 `psql` 中繼命令 `\d tablename`，然後在訂閱者執行個體上建立相同的資料表，以執行該操作。下列程序會在發佈者 (來源) 上建立範例資料表，以供示範之用。

1. 使用 `psql` 連線至具有資料表的執行個體，您想要將該資料表用作訂閱者的來源。

   ```
   psql --host=source-instance.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password --dbname=labdb
   ```

   如果您沒有要複寫的現有資料表，則可以建立如下的範例資料表。

   1. 使用下列 SQL 陳述式建立範例資料表。

      ```
      CREATE TABLE docs_lab_table (a int PRIMARY KEY);
      ```

   1. 使用下列 SQL 陳述式，將產生的資料填入資料表中。

      ```
      INSERT INTO docs_lab_table VALUES (generate_series(1,5000));
      INSERT 0 5000
      ```

   1. 使用下列 SQL 陳述式，驗證資料是否存在於資料表中。

      ```
      SELECT count(*) FROM docs_lab_table;
      ```

1. 將此 RDS for PostgreSQL 資料庫執行個體識別為發佈者節點，如下所示。

   ```
   SELECT pglogical.create_node(
       node_name := 'docs_lab_provider',
       dsn := 'host=source-instance.aws-region.rds.amazonaws.com port=5432 dbname=labdb');
    create_node
   -------------
      3410995529
   (1 row)
   ```

1. 將您要複寫的資料表新增至預設複寫集。如需複寫集的詳細資訊，請參閱 pglogical 文件中的 [Replication sets](https://github.com/2ndQuadrant/pglogical/tree/REL2_x_STABLE/docs#replication-sets) (複寫集)。

   ```
   SELECT pglogical.replication_set_add_table('default', 'docs_lab_table', 'true', NULL, NULL);
    replication_set_add_table
     ---------------------------
     t
     (1 row)
   ```

發佈者節點設定完成。您現在可以設定訂閱者節點，從發佈者接收更新。

**設定訂閱者節點並建立訂閱來接收更新**

這些步驟假設 RDS for PostgreSQL 資料庫執行個體已使用 `pglogical` 延伸模組進行設定。如需詳細資訊，請參閱[設定 pglogical 延伸模組](Appendix.PostgreSQL.CommonDBATasks.pglogical.basic-setup.md)。

1. 使用 `psql` 來連線至您想要從發佈者接收更新的執行個體。

   ```
   psql --host=target-instance.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password --dbname=labdb
   ```

1. 在訂閱者 RDS for PostgreSQL 資料庫執行個體上，建立存在於發佈者上的相同資料表。在此範例中，資料表是 `docs_lab_table`。您可以建立資料表，如下所示。

   ```
   CREATE TABLE docs_lab_table (a int PRIMARY KEY);
   ```

1. 驗證此資料表是否為空的。

   ```
   SELECT count(*) FROM docs_lab_table;
    count
   -------
     0
   (1 row)
   ```

1. 將此 RDS for PostgreSQL 資料庫執行個體識別為訂閱者節點，如下所示。

   ```
   SELECT pglogical.create_node(
       node_name := 'docs_lab_target',
       dsn := 'host=target-instance.aws-region.rds.amazonaws.com port=5432 sslmode=require dbname=labdb user=postgres password=********');
    create_node
   -------------
      2182738256
   (1 row)
   ```

1. 建立訂閱。

   ```
   SELECT pglogical.create_subscription(
      subscription_name := 'docs_lab_subscription',
      provider_dsn := 'host=source-instance.aws-region.rds.amazonaws.com port=5432 sslmode=require dbname=labdb user=postgres password=*******',
      replication_sets := ARRAY['default'],
      synchronize_data := true,
      forward_origins := '{}' );  
    create_subscription
   ---------------------
   1038357190
   (1 row)
   ```

   完成此步驟時，會在訂閱者上的資料表中建立來自發佈者上資料表的資料。您可以使用下列 SQL 查詢來驗證是否已發生此情況。

   ```
   SELECT count(*) FROM docs_lab_table;
    count
   -------
     5000
   (1 row)
   ```

從此開始，對發佈者上資料表所做的變更會複寫到訂閱者上的資料表。

# 在重大升級之後重新建立邏輯複寫
<a name="Appendix.PostgreSQL.CommonDBATasks.pglogical.recover-replication-after-upgrade"></a>

在對設為邏輯複寫之發佈者節點的 RDS for PostgreSQL 資料庫執行個體執行主要版本升級之前，您必須捨棄所有複寫槽，即使是未作用中的複寫槽也一樣。建議您暫時從發佈者節點轉移資料庫交易、捨棄複寫槽、升級 RDS for PostgreSQL 資料庫執行個體，然後重新建立並重新啟動複寫。

複寫槽僅託管於發佈者節點上。邏輯複寫案例中的 RDS for PostgreSQL 訂閱者節點沒有要捨棄的複寫槽，但在其指定為具有發佈者訂閱的訂閱者節點時，無法升級至主要版本。在升級 RDS for PostgreSQL 訂閱者節點之前，請先捨棄訂閱和節點。如需詳細資訊，請參閱 [管理 RDS for PostgreSQL 的邏輯複寫槽](Appendix.PostgreSQL.CommonDBATasks.pglogical.handle-slots.md)。

## 判斷邏輯複寫是否已中斷
<a name="Appendix.PostgreSQL.CommonDBATasks.pglogical.recover-replication-after-upgrade.identifying-the-issue"></a>

您可以查詢發佈者節點或訂閱者節點，來判斷複寫程序是否已中斷，如下所示。

**檢查發佈者節點**
+ 使用 `psql` 連線到發佈者節點，然後查詢 `pg_replication_slots` 函數。請注意作用中資料欄中的值。通常，這會傳回 `t` (true)，表明複寫作用中。如果查詢傳回 `f` (false)，表示已停止複寫至訂閱者。

  ```
  SELECT slot_name,plugin,slot_type,active FROM pg_replication_slots;
                      slot_name              |      plugin      | slot_type | active
  -------------------------------------------+------------------+-----------+--------
   pgl_labdb_docs_labcb4fa94_docs_lab3de412c | pglogical_output | logical   | f
  (1 row)
  ```

**檢查訂閱者節點**

在訂閱者節點上，您可以採取三種不同的方式來檢查複寫的狀態。
+ 查看訂閱者節點上的 PostgreSQL 日誌，以找出失敗訊息。日誌會以包含結束代碼 1 的訊息識別失敗，如下所示。

  ```
  2022-07-06 16:17:03 UTC::@:[7361]:LOG: background worker "pglogical apply 16404:2880255011" (PID 14610) exited with exit code 1
  2022-07-06 16:19:44 UTC::@:[7361]:LOG: background worker "pglogical apply 16404:2880255011" (PID 21783) exited with exit code 1
  ```
+ 查詢 `pg_replication_origin` 函數。使用 `psql` 連線至訂閱者節點上的資料庫，然後查詢 `pg_replication_origin` 函數，如下所示。

  ```
  SELECT * FROM pg_replication_origin;
   roident | roname
  ---------+--------
  (0 rows)
  ```

  空白結果集表示複寫已中斷。通常，您會看到如下輸出。

  ```
     roident |                       roname
    ---------+----------------------------------------------------
           1 | pgl_labdb_docs_labcb4fa94_docs_lab3de412c
    (1 row)
  ```
+ 查詢 `pglogical.show_subscription_status` 函數，如下列範例所示。

  ```
  SELECT subscription_name,status,slot_name FROM pglogical.show_subscription_status();
       subscription_name | status |              slot_name
  ---====----------------+--------+-------------------------------------
   docs_lab_subscription | down   | pgl_labdb_docs_labcb4fa94_docs_lab3de412c
  (1 row)
  ```

  此輸出表明複寫已中斷。其狀態為 `down`。通常，輸出會將狀態顯示為 `replicating`。

如果您的邏輯複寫程序已中斷，您可以遵循下列步驟重新建立複寫。

**重新建立發佈者與訂閱者節點之間的邏輯複寫**

若要重新建立複寫，首先中斷訂閱者與發佈者節點的連線，然後重新建立訂閱，如下列步驟所述。

1. 使用 `psql` 連線至訂閱者節點，如下所示。

   ```
   psql --host=222222222222.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password --dbname=labdb
   ```

1. 使用 `pglogical.alter_subscription_disable` 函數停用訂閱。

   ```
   SELECT pglogical.alter_subscription_disable('docs_lab_subscription',true);
    alter_subscription_disable
   ----------------------------
    t
   (1 row)
   ```

1. 透過查詢 `pg_replication_origin` 取得發佈者節點的識別符，如下所示。

   ```
   SELECT * FROM pg_replication_origin;
    roident |               roname
   ---------+-------------------------------------
          1 | pgl_labdb_docs_labcb4fa94_docs_lab3de412c
   (1 row)
   ```

1. 使用上一個步驟的回應搭配 `pg_replication_origin_create` 命令，來指派訂閱可在重新建立時使用的識別符。

   ```
   SELECT pg_replication_origin_create('pgl_labdb_docs_labcb4fa94_docs_lab3de412c');
     pg_replication_origin_create
   ------------------------------
                               1
   (1 row)
   ```

1. 透過傳送訂閱的名稱來開啟訂閱，其狀態為 `true`，如下列範例所示。

   ```
   SELECT pglogical.alter_subscription_enable('docs_lab_subscription',true);
     alter_subscription_enable
   ---------------------------
    t
   (1 row)
   ```

檢查節點的狀態。其狀態應為 `replicating`，如這個範例所示。

```
SELECT subscription_name,status,slot_name
  FROM pglogical.show_subscription_status();
             subscription_name |   status    |              slot_name
-------------------------------+-------------+-------------------------------------
 docs_lab_subscription         | replicating | pgl_labdb_docs_lab98f517b_docs_lab3de412c
(1 row)
```

檢查發佈者節點上訂閱者複寫槽的狀態。複寫槽的 `active` 資料欄應傳回 `t` (true)，表示已重新建立複寫。

```
SELECT slot_name,plugin,slot_type,active
  FROM pg_replication_slots;
                    slot_name              |      plugin      | slot_type | active
-------------------------------------------+------------------+-----------+--------
 pgl_labdb_docs_lab98f517b_docs_lab3de412c | pglogical_output | logical   | t
(1 row)
```

# 管理 RDS for PostgreSQL 的邏輯複寫槽
<a name="Appendix.PostgreSQL.CommonDBATasks.pglogical.handle-slots"></a>

在對充當邏輯複寫案例中發佈者節點的 RDS for PostgreSQL 資料庫執行個體執行主要版本升級之前，您必須捨棄執行個體上的複寫槽。主要版本升級預先檢查程序會通知您，除非捨棄複寫槽，否則升級無法繼續進行。

若要從 RDS for PostgreSQL 資料庫執行個體中捨棄複寫槽，請先捨棄訂閱，然後捨棄複寫槽。

若要識別已使用 `pglogical` 延伸模組建立的複寫槽，請登入每個資料庫並取得節點的名稱。查詢訂閱者節點時，您會在輸出中同時取得發佈者和訂閱者節點，如本範例所示。

```
SELECT * FROM pglogical.node;
node_id   |     node_name
------------+-------------------
 2182738256 | docs_lab_target
 3410995529 | docs_lab_provider
(2 rows)
```

您可以使用下列查詢，取得有關訂閱的詳細資訊。

```
SELECT sub_name,sub_slot_name,sub_target
  FROM pglogical.subscription;
 sub_name |         sub_slot_name          | sub_target
----------+--------------------------------+------------
  docs_lab_subscription     | pgl_labdb_docs_labcb4fa94_docs_lab3de412c | 2182738256
(1 row)
```

您現在可以捨棄訂閱，如下所示。

```
SELECT pglogical.drop_subscription(subscription_name := 'docs_lab_subscription');
 drop_subscription
-------------------
                 1
(1 row)
```

捨棄訂閱之後，您可以刪除節點。

```
SELECT pglogical.drop_node(node_name := 'docs-lab-subscriber');
 drop_node
-----------
 t
(1 row)
```

您可以驗證節點是否不再存在，如下所示。

```
SELECT * FROM pglogical.node;
 node_id | node_name
---------+-----------
(0 rows)
```

# pglogical 延伸模組的參數參考
<a name="Appendix.PostgreSQL.CommonDBATasks.pglogical.reference"></a>

在資料表中，您可以尋找與 `pglogical` 延伸模組相關聯的參數。`pglogical.conflict_log_level` 和 `pglogical.conflict_resolution` 這類參數用來處理更新衝突。對從發佈者訂閱變更的相同資料表進行本機變更時，可能會出現衝突。在各種案例期間 (例如雙向複寫或從相同發佈者複寫多個訂閱者時)，也會發生衝突。如需詳細資訊，請參閱[使用 pglogical 進行 PostgreSQL 雙向複寫](https://aws.amazon.com/blogs/database/postgresql-bi-directional-replication-using-pglogical/)。


| 參數 | Description | 
| --- | --- | 
| pglogical.batch\$1inserts | 可能情況下批次插入。依預設不會設定。變更為 '1' 以開啟、變更為 '0' 以關閉。 | 
| pglogical.conflict\$1log\$1level | 設定用於記錄已解決衝突的日誌層級。支援的字串值為 debug5、debug4、debug3、debug2、debug1、info、notice、warning、error、log、fatal、panic。 | 
| pglogical.conflict\$1resolution | 設定用來在衝突可解決時解決衝突的方法。支援的字串值為 error、apply\$1remote、keep\$1local、last\$1update\$1wins、first\$1update\$1wins。 | 
| pglogical.extra\$1connection\$1options | 要新增到所有對等節點連線的連線選項。 | 
| pglogical.synchronous\$1commit | pglogical 特定的同步遞交值 | 
| pglogical.use\$1spi | 使用 SPI (伺服器程式設計介面) 而不是低階 API 來套用變更。設為 '1' 以開啟、設為 '0' 以關閉。如需 SPI 的詳細資訊，請參閱 PostgreSQL 文件中的 [Server Programming Interface](https://www.postgresql.org/docs/current/spi.html) (伺服器程式設計介面)。 | 

# 使用 pgactive 來支援主動-主動式複寫
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive"></a>

`pgactive` 延伸模組使用主動-主動式複寫來支援和協調多個 RDS for PostgreSQL 資料庫上的寫入操作。Amazon RDS for PostgreSQL 的下列版本支援 `pgactive` 延伸模組：
+ RDS for PostgreSQL 17.0 版和更新版本
+ RDS for PostgreSQL 16.1 和更高的第 16 版
+ RDS for PostgreSQL 15.4-R2 及更高的 15 版本
+ RDS for PostgreSQL 14.10 及更高的 14 版本
+ RDS for PostgreSQL 13.13 及更高的 13 版本
+ RDS for PostgreSQL 12.17 及更高的 12 版本
+ RDS for PostgreSQL 11.22

**注意**  
當複寫組態中的多個資料庫上有寫入操作時，可能會發生衝突。如需詳細資訊，請參閱[處理主動-主動式複寫中的衝突](Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-conflicts.md)

**Topics**
+ [pgactive 延伸模組的現制](#Appendix.PostgreSQL.CommonDBATasks.pgactive.requirements-limitations)
+ [初始化 pgactive 延伸模組功能](Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup.md)
+ [針對 RDS for PostgreSQL 資料庫執行個體設定主動-主動式複寫](Appendix.PostgreSQL.CommonDBATasks.pgactive.setup-replication.md)
+ [測量 pgactive 成員之間的複寫延遲](Appendix.PostgreSQL.CommonDBATasks.pgactive.replicationlag.md)
+ [設定 pgactive 延伸模組的參數設定](Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.md)
+ [了解主動-主動衝突](Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.replication.md)
+ [了解 pgactive 結構描述](Appendix.PostgreSQL.CommonDBATasks.pgactive.schema.md)
+ [pgactive 函數參考](pgactive-functions-reference.md)
+ [處理主動-主動式複寫中的衝突](Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-conflicts.md)
+ [處理主動-主動式複寫中的序列](Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-sequences.md)

## pgactive 延伸模組的現制
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.requirements-limitations"></a>
+ 所有資料表都需有主索引鍵，否則不允許更新和刪除操作。主索引鍵欄中的值不應更新。
+ 序列可能有間隙，有時可能不按順序。序列未複寫。如需詳細資訊，請參閱[處理主動-主動式複寫中的序列](Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-sequences.md)。
+ DDL 和大型物件未複寫。
+ 次要唯一索引可能會導致資料差異。
+ 群組中所有節點的定序都必須相同。
+ 節點之間的負載平衡是一種反模式。
+ 大型交易可能造成複寫延遲。

# 初始化 pgactive 延伸模組功能
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup"></a>

若要在 RDS for PostgreSQL 資料庫執行個體上初始化 `pgactive` 延伸模組，請將 `rds.enable_pgactive` 參數值設定為 `1`，然後在資料庫中建立延伸模組。這樣做就會自動開啟參數 `rds.logical_replication` 和 `track_commit_timestamp`，並將 `wal_level` 的值設定為 `logical`。

您必須具有做為 `rds_superuser` 角色的許可，才能執行這些任務。

您可以使用 AWS 管理主控台 或 AWS CLI 來建立所需的 RDS for PostgreSQL 資料庫執行個體。下列步驟假設您的 RDS for PostgreSQL 資料庫執行個體與自訂資料庫參數群組相關聯。如需建立自訂資料庫參數群組的相關資訊，請參閱 [Amazon RDS 的參數群組](USER_WorkingWithParamGroups.md)。

## 主控台
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup.CON"></a>

**若要初始化 pgactive 延伸模組功能**

1. 登入 AWS 管理主控台 ，並在 [https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/)：// 開啟 Amazon RDS 主控台。

1. 在導覽窗格中，選擇您的 RDS for PostgreSQL 資料庫執行個體。

1. 針對您的 RDS for PostgreSQL 資料庫執行個體開啟**組態**索引標籤。在執行個體詳細資訊中，找到**資料庫執行個體參數群組**連結。

1. 選擇連結以開啟與您的 RDS for PostgreSQL 資料庫執行個體相關聯的自訂參數。

1. 找到 `rds.enable_pgactive` 參數，並將其設定為 `1` 以初始化 `pgactive` 功能。

1. 選擇**儲存變更**。

1. 從 Amazon RDS 主控台的導覽窗格中，選擇**資料庫**。

1. 選取您的 RDS for PostgreSQL 資料庫執行個體，然後從**動作**選單中選擇**重新開機**。

1. 確認資料庫執行個體重新開機，以讓您的變更生效。

1. 當資料庫執行個體可用時，您可以使用 `psql` 或任何其他 PostgreSQL 用戶端連線至 RDS for PostgreSQL 資料庫執行個體。

   下列範例假設您的 RDS for PostgreSQL 資料庫執行個體擁有名為 *postgres* 的預設資料庫。

   ```
   psql --host=mydb.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password=PASSWORD --dbname=postgres
   ```

1. 若要驗證 pgactive 是否已初始化，請執行下列命令。

   ```
   postgres=>SELECT setting ~ 'pgactive' 
   FROM pg_catalog.pg_settings
   WHERE name = 'shared_preload_libraries';
   ```

   如果 `pgactive` 在 `shared_preload_libraries` 中，則上述命令將傳回以下內容：

   ```
   ?column? 
   ----------
    t
   ```

## AWS CLI
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup.CLI"></a>

**若要初始化 pgactive 延伸模組功能**

若要`pgactive`使用 初始化 AWS CLI，請呼叫 [modify-db-parameter-group](https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-parameter-group.html) 操作來修改自訂參數群組中的特定參數，如下列程序所示。

1. 使用下列 AWS CLI 命令將 `rds.enable_pgactive` 設定為 `1`，以初始化 RDS for PostgreSQL 資料庫執行個體`pgactive`的功能。

   ```
   postgres=>aws rds modify-db-parameter-group \
      --db-parameter-group-name custom-param-group-name \
      --parameters "ParameterName=rds.enable_pgactive,ParameterValue=1,ApplyMethod=pending-reboot" \
      --region aws-region
   ```

1. 使用以下 AWS CLI 命令重新啟動 RDS for PostgreSQL 資料庫執行個體，以便初始化`pgactive`程式庫。

   ```
   aws rds reboot-db-instance \
       --db-instance-identifier your-instance \
       --region aws-region
   ```

1. 當執行個體可用時，請使用 `psql` 連線至 RDS for PostgreSQL 資料庫執行個體。。

   ```
   psql --host=mydb.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=master user --password=PASSWORD --dbname=postgres
   ```

1. 若要驗證 pgactive 是否已初始化，請執行下列命令。

   ```
   postgres=>SELECT setting ~ 'pgactive' 
   FROM pg_catalog.pg_settings
   WHERE name = 'shared_preload_libraries';
   ```

   如果 `pgactive` 在 `shared_preload_libraries` 中，則上述命令將傳回以下內容：

   ```
   ?column? 
   ----------
    t
   ```

# 針對 RDS for PostgreSQL 資料庫執行個體設定主動-主動式複寫
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.setup-replication"></a>

下列程序說明如何在兩個 RDS for PostgreSQL 資料庫執行個體 (其中 `pgactive` 可用) 之間啟動主動-主動複寫。若要執行多區域高可用性範例，您需要在兩個不同的區域部署 Amazon RDS for PostgreSQL 執行個體，並設定 VPC 對等互連。如需詳細資訊，請參閱 [VPC 對等互連](https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html)。

**注意**  
在多個地區之間傳送流量可能會產生額外費用。

這些步驟假設 RDS for PostgreSQL 資料庫執行個體已使用 `pgactive` 延伸模組啟用。如需詳細資訊，請參閱[初始化 pgactive 延伸模組功能](Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup.md)。

**若要設定第一個具有 `pgactive` 延伸模組的 RDS for PostgreSQL 資料庫執行個體**

下列範例說明如何建立 `pgactive` 群組，以及在 RDS for PostgreSQL 資料庫執行個體上建立 `pgactive` 延伸模組所需的其他步驟。

1. 使用 `psql` 或其他用戶端工具連線至您的第一個 RDS for PostgreSQL 資料庫執行個體。

   ```
   psql --host=firstinstance.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password=PASSWORD --dbname=postgres
   ```

1. 使用下列命令在 RDS for PostgreSQL 執行個體上建立資料庫：

   ```
   postgres=> CREATE DATABASE app;
   ```

1. 使用下列命令將連線切換至新資料庫：

   ```
   \c app
   ```

1. 使用下列 SQL 陳述式建立並填入範例資料表：

   1. 使用下列 SQL 陳述式建立範例資料表。

      ```
      app=> CREATE SCHEMA inventory;
      CREATE TABLE inventory.products (
      id int PRIMARY KEY, product_name text NOT NULL,
      created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP);
      ```

   1. 使用下列 SQL 陳述式在資料表中填入一些範例資料。

      ```
      app=> INSERT INTO inventory.products (id, product_name)
      VALUES (1, 'soap'), (2, 'shampoo'), (3, 'conditioner');
      ```

   1. 使用下列 SQL 陳述式，驗證資料是否存在於資料表中。

      ```
       app=>SELECT count(*) FROM inventory.products;
      
       count
      -------
       3
      ```

1. 在現有資料庫上建立 `pgactive` 延伸模組。

   ```
   app=> CREATE EXTENSION pgactive;
   ```

1. 若要安全地建立並初始化 pgactive 群組，請使用下列命令：

   ```
   app=>
   -- connection info for endpoint1
   CREATE SERVER pgactive_server_endpoint1
       FOREIGN DATA WRAPPER pgactive_fdw
       OPTIONS (host '<endpoint1>', dbname 'app');
   CREATE USER MAPPING FOR postgres
       SERVER pgactive_server_endpoint1
       OPTIONS (user 'postgres', password '<password>');
         -- connection info for endpoint2
   CREATE SERVER pgactive_server_endpoint2
       FOREIGN DATA WRAPPER pgactive_fdw
       OPTIONS (host '<endpoint2>', dbname 'app');
   CREATE USER MAPPING FOR postgres
       SERVER pgactive_server_endpoint2
       OPTIONS (user 'postgres', password '<password>');
   ```

   現在您可以初始化複寫群組並新增第一個執行個體：

   ```
   SELECT pgactive.pgactive_create_group(
       node_name := 'endpoint1-app',
       node_dsn := 'user_mapping=postgres pgactive_foreign_server=pgactive_server_endpoint1'
   
   );
   ```

   使用下列命令做為替代但較不安全的方法，來建立和初始化 pgactive 群組：

   ```
   app=> SELECT pgactive.pgactive_create_group(
       node_name := 'node1-app',
       node_dsn := 'dbname=app host=firstinstance.111122223333.aws-region.rds.amazonaws.com user=postgres password=PASSWORD');
   ```

   node1-app 是您指派的名稱，用於單獨識別 `pgactive` 群組中的節點。
**注意**  
若要在可公開存取的資料庫執行個體上成功執行此步驟，您必須將 `rds.custom_dns_resolution` 參數設定為 `1` 以將它開啟。

1. 若要檢查資料庫執行個體是否已就緒，請使用下列命令：

   ```
   app=> SELECT pgactive.pgactive_wait_for_node_ready();
   ```

   如果命令成功，您會看到以下輸出內容：

   ```
   pgactive_wait_for_node_ready 
   ------------------------------ 
   (1 row)
   ```

**若要設定第二個 RDS for PostgreSQL 執行個體，並將其加入 `pgactive` 群組**

下列範例說明如何建立將 RDS for PostgreSQL 資料庫執行個體加入 `pgactive` 群組，以及在資料庫執行個體上建立 `pgactive` 延伸模組所需的其他步驟。

這些步驟假設已有另一個 RDS for PostgreSQL 資料庫執行個體使用 `pgactive` 延伸模組設定完成。如需詳細資訊，請參閱[初始化 pgactive 延伸模組功能](Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup.md)。

1. 使用 `psql` 來連線至您想要從發佈者接收更新的執行個體。

   ```
   psql --host=secondinstance.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password=PASSWORD --dbname=postgres
   ```

1. 使用下列命令在第二個 RDS for PostgreSQL 資料庫執行個體上建立資料庫：

   ```
   postgres=> CREATE DATABASE app;
   ```

1. 使用下列命令將連線切換至新資料庫：

   ```
   \c app
   ```

1. 在現有資料庫上建立 `pgactive` 延伸模組。

   ```
   app=> CREATE EXTENSION pgactive;
   ```

1. 使用下列命令，以更安全的方法將 RDS for PostgreSQL 第二個資料庫執行個體加入 `pgactive` 群組：

   ```
   -- connection info for endpoint1
   CREATE SERVER pgactive_server_endpoint1
       FOREIGN DATA WRAPPER pgactive_fdw
       OPTIONS (host '<endpoint1>', dbname 'app');
   CREATE USER MAPPING FOR postgres
       SERVER pgactive_server_endpoint1
       OPTIONS (user 'postgres', password '<password>');
   
   -- connection info for endpoint2
   CREATE SERVER pgactive_server_endpoint2
       FOREIGN DATA WRAPPER pgactive_fdw
       OPTIONS (host '<endpoint2>', dbname 'app');
   CREATE USER MAPPING FOR postgres
       SERVER pgactive_server_endpoint2
       OPTIONS (user 'postgres', password '<password>');
   ```

   ```
   SELECT pgactive.pgactive_join_group(
       node_name := 'endpoint2-app',
       node_dsn := 'user_mapping=postgres pgactive_foreign_server=pgactive_server_endpoint2',
       join_using_dsn := 'user_mapping=postgres pgactive_foreign_server=pgactive_server_endpoint1'
   );
   ```

   使用下列命令做為替代但較不安全的方法，將 RDS for PostgreSQL 第二個資料庫執行個體加入 `pgactive` 群組

   ```
   app=> SELECT pgactive.pgactive_join_group(
   node_name := 'node2-app',
   node_dsn := 'dbname=app host=secondinstance.111122223333.aws-region.rds.amazonaws.com user=postgres password=PASSWORD',
   join_using_dsn := 'dbname=app host=firstinstance.111122223333.aws-region.rds.amazonaws.com user=postgres password=PASSWORD');
   ```

   node2-app 是您指派的名稱，用於單獨識別 `pgactive` 群組中的節點。

1. 若要檢查資料庫執行個體是否已就緒，請使用下列命令：

   ```
   app=> SELECT pgactive.pgactive_wait_for_node_ready(); 
   ```

   如果命令成功，您會看到以下輸出內容：

   ```
   pgactive_wait_for_node_ready 
   ------------------------------ 
   (1 row)
   ```

   如果第一個 RDS for PostgreSQL 資料庫相對較大，您會看到 `pgactive.pgactive_wait_for_node_ready()` 發出還原操作的進度報告。輸出結果類似如下：

   ```
   NOTICE:  restoring database 'app', 6% of 7483 MB complete
   NOTICE:  restoring database 'app', 42% of 7483 MB complete
   NOTICE:  restoring database 'app', 77% of 7483 MB complete
   NOTICE:  restoring database 'app', 98% of 7483 MB complete
   NOTICE:  successfully restored database 'app' from node node1-app in 00:04:12.274956
    pgactive_wait_for_node_ready 
   ------------------------------ 
   (1 row)
   ```

   從這裡開始，`pgactive` 會在兩個資料庫執行個體之間同步資料。

1. 您可以使用下列命令來驗證第二個資料庫執行個體的資料庫是否有資料：

   ```
   app=> SELECT count(*) FROM inventory.products;
   ```

   如果資料已成功同步，您會看到下列輸出內容：

   ```
    count
   -------
    3
   ```

1. 執行下列命令以插入新值：

   ```
   app=> INSERT INTO inventory.products (id, product_name) VALUES (4, 'lotion');
   ```

1. 連線至第一個資料庫執行個體的資料庫，然後執行下列查詢：

   ```
   app=> SELECT count(*) FROM inventory.products;
   ```

   如果主動-主動式複寫已初始化，則會輸出類似下列內容：

   ```
   count
   -------
    4
   ```

**從 `pgactive` 群組卸離並移除資料庫執行個體**

您可以利用下列步驟將資料庫執行個體從 `pgactive` 群組卸離並移除：

1. 您可以使用下列命令將第二個資料庫執行個體從第一個資料庫執行個體卸離：

   ```
   app=> SELECT * FROM pgactive.pgactive_detach_nodes(ARRAY[‘node2-app']);
   ```

1. 使用下列命令從第二個資料庫執行個體移除 `pgactive` 延伸模組：

   ```
   app=> SELECT * FROM pgactive.pgactive_remove();
   ```

   若要強制移除延伸模組：

   ```
   app=> SELECT * FROM pgactive.pgactive_remove(true);
   ```

1. 使用以下命令刪除延伸模組：

   ```
   app=> DROP EXTENSION pgactive;
   ```

# 測量 pgactive 成員之間的複寫延遲
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.replicationlag"></a>

您可以使用下列查詢來檢視 `pgactive` 成員之間的複寫延遲。在每個 `pgactive` 節點上執行此查詢以取得全貌。

```
    
app=> SELECT * FROM pgactive.pgactive_get_replication_lag_info();
│-[ RECORD 1 ]--------+---------------------------------------------
│node_name            | node2-app
│node_sysid           | 7481018224801653637
│application_name     | pgactive:7481018224801653637:send
│slot_name            | pgactive_16385_7481018224801653637_0_16385__
│active               | t
│active_pid           | 783486
│pending_wal_decoding | 0
│pending_wal_to_apply | 0
│restart_lsn          | 0/2108150
│confirmed_flush_lsn  | 0/2154690
│sent_lsn             | 0/2154690
│write_lsn            | 0/2154690
│flush_lsn            | 0/2154690
│replay_lsn           | 0/2154690
│-[ RECORD 2 ]--------+---------------------------------------------
│node_name            | node1-app
│node_sysid           | 7481018033434600853
│application_name     | pgactive:7481018033434600853:send
│slot_name            | pgactive_16385_7481018033434600853_0_16385__
│active               | t
│active_pid           | 783488
│pending_wal_decoding | 0
│pending_wal_to_apply | 0
│restart_lsn          | 0/20F5AD0
│confirmed_flush_lsn  | 0/214EF68
│sent_lsn             | 0/214EF68
│write_lsn            | 0/214EF68
│flush_lsn            | 0/214EF68
│replay_lsn           | 0/214EF68
```

至少監控下列診斷：

active  
設定作用中為 false 時的警示，表示插槽目前未使用 (訂閱者執行個體已與發佈者中斷連線)。

pending\$1wal\$1decoding  
在 PostgreSQL 的邏輯複寫中，WAL 檔案會以二進位格式儲存。發佈者必須解碼這些 WAL 變更，並將其轉換為邏輯變更 (例如插入、更新或刪除操作)。  
指標 pending\$1wal\$1decoding 會顯示在發佈者端等待解碼的 WAL 檔案數目。  
此數字可能會因為下列因素而增加：  
+ 當訂閱者未連線時，作用中狀態將為 false，而 pending\$1wal\$1decoding 將會增加
+ 插槽處於作用中狀態，但發佈者無法跟上 WAL 變更的數量

pending\$1wal\$1to\$1apply  
指標 pending\$1wal\$1apply 表示在訂閱者端等待套用的 WAL 檔案數目。  
有幾個因素可能會阻止訂閱者套用變更，並可能導致磁碟已滿的情況：  
+ 結構描述差異 - 例如，當您對名為範例的資料表進行 WAL 串流的變更，但訂閱者端不存在該資料表時
+ 主索引鍵資料行中的值已更新
+ 次要唯一索引可能會導致資料差異。

# 設定 pgactive 延伸模組的參數設定
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters"></a>

您可以使用下列查詢來檢視與 `pgactive` 延伸模組相關聯的所有參數。

```
app=> SELECT * FROM pg_settings WHERE name LIKE 'pgactive.%';
```

您可以使用各種參數來設定 `pgactive` 延伸模組。這些參數可以透過 AWS 管理主控台 或 AWS CLI 界面設定。

## 主要 pgactive 延伸模組參數
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.mainparams"></a>

下表提供 `pgactive` 延伸模組主要參數的參考：


| 參數 | 單位 | 預設 | Description | 
| --- | --- | --- | --- | 
| pgactive.conflict\$1logging\$1include\$1tuples | `boolean` | –  | 記錄 `pgactive` 延伸模組的完整元組資訊。  需要重新啟動伺服器，變更才會生效。  | 
| pgactive.log\$1conflicts\$1to\$1table | `boolean` | –  | 決定 `pgactive` 延伸模組是否將偵測到的衝突記錄到 `pgactive.pgactive_conflict_history` 資料表。如需詳細資訊，請參閱衝突記錄以取得詳細資訊。  需要重新啟動伺服器，變更才會生效。  | 
| pgactive.log\$1conflicts\$1to\$1logfile | `boolean` | –  | 決定 `pgactive` 延伸模組是否將偵測到的衝突記錄到 PostgreSQL 日誌檔案。如需詳細資訊，請參閱衝突記錄以取得詳細資訊。  需要重新啟動伺服器，變更才會生效。  | 
| pgactive.synchronous\$1commit | `boolean` | off | 決定 pgactive 套用工作者的遞交行為。當停用 (關閉) 時，套用工作者會執行非同步遞交，這可在套用操作期間改善 PostgreSQL 輸送量，但會延遲對上游的重新執行確認。將其設定為 `off` 一律是安全的，不會導致交易遺失或略過。此設定只會影響下游節點上磁碟排清的時間，以及確認傳送至上游的時間。系統會延遲傳送重新執行排清確認，直到透過檢查點或定期工作等不相關的操作將遞交排清至磁碟為止。不過，如果上游在 `synchronous_standby_names` 中列出下游，則將其設定為 `off` 會導致上游的同步遞交需要更長的時間才能向用戶端報告成功。在此案例中，請將參數設定為 `on`。  即使此參數設為 `on` 且節點列在 `synchronous_standby_names` 中，在主動-主動組態中仍可能發生複寫衝突。這是因為系統缺少節點間鎖定和全域快照管理，允許不同節點上的並行交易修改相同的元組。此外，交易只有在上游節點上遞交之後才會開始複寫。啟用同步遞交不會將 pgactive 延伸模組轉換為始終一致的系統。  | 
| pgactive.temp\$1dump\$1directory | `string` | – | 定義初始設定期間資料庫複製操作所需的臨時儲存路徑。此目錄必須可由 postgres 使用者寫入，並且有足夠的儲存空間來包含完整的資料庫傾印。系統只會在具有邏輯複製操作的初始資料庫設定期間使用此位置。`pgactive_init_copy command` 不會使用此參數。 | 
| pgactive.max\$1ddl\$1lock\$1delay | `milliseconds` | `-1` | 指定強制中止並行寫入交易之前 DDL 鎖定的等待時間上限。預設值為 `-1`，採用 `max_standby_streaming_delay` 中設定的值。此參數接受時間單位。例如，您可以將其設定為 10s，代表 10 秒。在此等待期間，系統會嘗試取得 DDL 鎖定，同時等待進行中的寫入交易遞交或復原。如需詳細資訊，請參閱「DDL 鎖定」。 | 
| pgactive.ddl\$1lock\$1timeout | `milliseconds` | `-1` | 指定 DDL 鎖定嘗試等待多久才能取得鎖定。預設值為 `-1`，使用 lock\$1timeout 中指定的值。您可以使用時間單位設定此參數，例如 10s，代表 10 秒。此計時器只會控制取得 DDL 鎖定的等待期間。一旦系統取得鎖定並開始 DDL 操作，計時器就會停止。此參數不會限制可保留 DDL 鎖定的持續時間總計或整體 DDL 操作時間。若要控制操作的持續時間總計，請改用 `statement_timeout`。如需詳細資訊，請參閱「DDL 鎖定」。 | 
| pgactive.debug\$1trace\$1ddl\$1locks\$1level | `boolean` | –  | 覆寫 `pgactive` 延伸模組中 DDL 鎖定操作的預設偵錯日誌層級。設定時，此設定會導致 DDL 鎖定相關的訊息在 LOG 偵錯層級發出，而不是其預設層級。使用此參數來監控 DDL 鎖定活動，而無需在整個伺服器上啟用詳細 `DEBUG1` 或 `DEBUG2` 日誌層級。 可用日誌層級，依詳細程度增加： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) 如需監控選項的詳細資訊，請參閱「監控全域 DDL 鎖定」。  當您重新載入組態時，此設定的變更會生效。您不需要重新啟動伺服器。   | 

## 其他 pgactive 延伸模組參數
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.addparams"></a>

下表顯示 `pgactive` 延伸模組可用的較不常用和內部組態選項。


| 參數 | 單位 | 預設 | Description | 
| --- | --- | --- | --- | 
| pgactive.debug\$1apply\$1delay | `integer` | – |  為在其 `pgactive.pgactive_connections` 項目中沒有明確套用延遲的已設定連線設定套用延遲 (以毫秒為單位)。此延遲是在節點建立或聯結時間期間設定，且 pgactive 在遞交後至少經過指定的毫秒數之前，不會在對等節點上重新執行交易。 主要用於在測試環境中模擬高延遲網路，以更輕鬆地建立衝突。例如，在節點 A 和 B 上延遲 500 毫秒的情況下，在節點 A 上插入值後，您有至少 500 毫秒的時間在節點 B 上執行衝突的插入。  需要重新載入伺服器或重新啟動套用工作者才能生效。  | 
| pgactive.connectability\$1check\$1duration | `integer` | –  | 指定資料庫工作者在失敗嘗試期間嘗試建立連線的持續時間 (以秒為單位)。工作者會每秒進行一次連線嘗試，直到連線成功或達到此逾時值為止。當資料庫引擎在工作者準備好建立連線之前啟動時，此設定很有用。 | 
| pgactive.skip\$1ddl\$1replication | `boolean` | `on` | 在已啟用 `pgactive` 的情況下，控制在 Amazon RDS 中複寫或處理 DDL 變更的方式。設定為 `on` 時，節點會像非 pgcctive 節點一樣處理 DDL 變更。使用此參數時適用以下要求： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) 您可以使用兩種超級使用者權限來修改此參數：全域、本機 (工作階段層級)。  不正確地變更此參數可能會中斷複寫設定。  | 
| pgactive.do\$1not\$1replicate | `boolean` | – | 此參數僅供內部使用。當您在交易中設定此參數時，變更不會複寫至資料庫叢集中的其他節點。  不正確地變更此參數可能會中斷複寫設定。  | 
| pgactive.discard\$1mismatched\$1row\$1attributes | `boolean` | –  | 此參數僅供專家使用。建議您只在針對特定複寫問題進行疑難排解時，才使用此參數。在下列情況時使用此參數： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) 此設定會覆寫下列錯誤訊息，並允許出現資料差異，讓複寫繼續：`cannot right-pad mismatched attributes; attno %u is missing in local table and remote row has non-null, non-dropped value for this attribute`  不正確地變更此參數可能會中斷複寫設定。   | 
| pgactive.debug\$1trace\$1replay | `boolean` | – | 設定為 `on` 時，它會針對下游套用工作者程序的每個遠端動作發出日誌訊息。日誌包括： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) 日誌也會擷取排入佇列的 DDL 命令和資料表捨棄。para> 根據預設，日誌不包含資料列欄位內容。若要在日誌中包含資料列值，您必須重新編譯並啟用下列旗標： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html)  啟用此記錄設定可能會影響效能。建議您僅在需要進行疑難排解時啟用它。當您重新載入組態時，此設定的變更會生效。您不需要重新啟動伺服器。   | 
| pgactive.extra\$1apply\$1connection\$1options |  | – | 您可以為具有 pgactive 節點的所有對等節點連線設定連線參數。這些參數會控制保持連線和 SSL 模式等設定。根據預設，pgactive 會使用下列連線參數： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) 若要覆寫預設參數，請使用下列類似命令： pgactive.extra\$1apply\$1connection\$1options = 'keepalives=0' 個別節點連線字串優先於這些設定和 pgactive 的內建連線選項。如需連線字串格式的詳細資訊，請參閱 [libpq 連線字串](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING)。 建議您保持預設保持連線設定為啟用狀態。只有在大型交易透過不可靠的網路完成時遇到問題的情況下，才停用保持連線。  建議您保持預設保持連線設定為啟用狀態。只有在大型交易透過不可靠的網路完成時遇到問題的情況下，才停用保持連線。當您重新載入組態時，此設定的變更會生效。您不需要重新啟動伺服器。  | 
| pgactive.init\$1node\$1parallel\$1jobs (int) |  | – | 指定 `pg_dump` 和 `pg_restore` 可在與 `pgactive.pgactive_join_group` 函數的邏輯節點聯結期間使用的平行任務數目。 當您重新載入組態時，此設定的變更會生效。您不需要重新啟動伺服器。 | 
| pgactive.max\$1nodes | `int` | 4 |  指定 pgactive 延伸模組群組中允許的節點數目上限。預設值為 4 個節點。設定此參數的值時，您必須考量下列事項： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) 您有兩種方式可以設定此參數：在組態檔案中，使用 `ALTER SYSTEM SET` 命令 此參數的預設值為 `4`，表示 `pgactive` 延伸模組群組在任何時間點最多可以有 4 個節點。  變更會在您重新啟動伺服器後生效。  | 
| pgactive.permit\$1node\$1identifier\$1getter\$1function\$1creation | `boolean` | – | 此參數僅供內部使用。啟用時，`pgactive` 延伸模組允許建立 pgactive 節點識別符 getter 函數。 | 

# 了解主動-主動衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.replication"></a>

當您在主動-主動模式下使用 pgactive 時，從多個節點寫入相同的資料表可能會產生資料衝突。雖然某些叢集系統使用分散式鎖定來防止並行存取，但 pgactive 採取了更樂觀的方法，更適合地理分散式應用程式。

有些資料庫叢集系統會使用分散式鎖定來防止並行資料存取。雖然此方法可在伺服器接近時運作，但它不支援地理分散式應用程式，因為它需要極低的延遲才能獲得良好的效能。pgactive 延伸模組使用樂觀的方法，而不是使用分散式鎖定 (悲觀方法)。這表示：
+ 協助您盡可能避免衝突。
+ 允許發生特定類型的衝突。
+ 在發生衝突時提供衝突解決方法。

此方法可讓您在建置分散式應用程式時更具彈性。

## 衝突的發生方式
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.howconflicts"></a>

如果所有涉及的交易都在相同節點上同時發生，則無法發生的事件序列會產生節點間衝突。由於節點只會在交易遞交之後交換變更，因此每個交易個別對其遞交的節點有效，但如果在同時完成其他工作的另一個節點上執行，則會無效。由於 pgactive 套用基本上會在其他節點上重新執行交易，如果套用的交易與在接收節點上遞交的交易之間發生衝突，則重新執行操作可能會失敗。

 當所有交易都在單一節點上執行時，大多數衝突不會發生的原因是 PostgreSQL 具有防止衝突的交易間通訊機制，包括：
+ UNIQUE 索引
+ 序列
+ 資料列和關聯鎖定
+ SERIALIZABLE 相依性追蹤

這裡的所有機制都是在交易之間進行通訊的方式，以防止不需要的並行問題

pgactive 可實現低延遲並妥善處理網路分割區，因為它不使用分散式交易管理員或鎖定管理員。不過，這表示不同節點上交易的執行彼此完全隔離。雖然隔離通常會改善資料庫一致性，但在這種情況下，您需要減少隔離以防止衝突。

## 衝突類型
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflicttypes"></a>

可能發生的衝突包括：

**Topics**
+ [PRIMARY KEY 或 UNIQUE 衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict1)
+ [INSERT/INSERT 衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict2)
+ [違反多個 UNIQUE 限制條件的 INSERT](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict3)
+ [UPDATE/UPDATE 衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict4)
+ [PRIMARY KEY 上的 UPDATE 衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict5)
+ [違反多個 UNIQUE 限制條件的 UPDATE](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict6)
+ [UPDATE/DELETE 衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict7)
+ [INSERT/UPDATE 衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict8)
+ [DELETE/DELETE 衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict9)
+ [外部索引鍵限制條件衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict10)
+ [排除限制條件衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict11)
+ [全域資料衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict12)
+ [鎖定衝突和死鎖中止](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict13)
+ [分歧衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict14)

### PRIMARY KEY 或 UNIQUE 衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict1"></a>

當多個操作嘗試以在單一節點上不可行的方式修改相同的資料列索引鍵時，就會發生資料列衝突。這些衝突代表最常見的資料衝突類型。

pgactive 透過 last-update-wins 處理或您的自訂衝突處理常式來解決偵測到的衝突。

資料列衝突包括：
+ INSERT 與 INSERT
+ INSERT 與 UPDATE
+ UPDATE 與 DELETE
+ INSERT 與 DELETE
+ DELETE 與 DELETE
+ INSERT 與 DELETE

### INSERT/INSERT 衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict2"></a>

當兩個不同節點上的 INSERT 建立具有相同 PRIMARY KEY 值 (或不存在 PRIMARY KEY 時相同的 UNIQUE 限制條件值) 的元組時，就會發生此最常見的衝突。

pgactivelink 使用來自原始主機的時間戳記來保留最新的元組，以解決 INSERT 衝突。您可以使用自訂衝突處理常式覆寫此預設行為。雖然此程序不需要特殊管理員動作，但請注意，pgactivelink 會捨棄所有節點的其中一個 INSERT 操作。除非您的自訂處理常式實作，否則不會自動合併資料。

pgactivelink 只能解決涉及單一限制條件違規的衝突。如果 INSERT 違反多個 UNIQUE 限制條件，您必須實作額外的衝突解決策略。

### 違反多個 UNIQUE 限制條件的 INSERT
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict3"></a>

INSERT/INSERT 衝突可能會違反多個 UNIQUE 限制條件，包括 PRIMARY KEY。pgactivelink 只能處理涉及單一 UNIQUE 限制條件的衝突。當衝突違反多個 UNIQUE 限制條件時，套用工作者會失敗並傳回下列錯誤：

`multiple unique constraints violated by remotely INSERTed tuple.`

在較舊版本中，此情況會產生「發散唯一性衝突」錯誤。

若要解決這些衝突，您必須採取手動動作。針對衝突的本機元組進行 DELETE 操作或進行 UPDATE 操作，以移除與新遠端元組的衝突。請注意，您可能需要處理多個衝突元組。目前，pgactivelink 不提供內建功能來忽略、捨棄或合併違反多個唯一限制條件的元組。

**注意**  
如需詳細資訊，請參閱違反多個 UNIQUE 限制條件的 UPDATE。

### UPDATE/UPDATE 衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict4"></a>

當兩個節點同時修改相同的元組而不變更其 PRIMARY KEY 時，就會發生此衝突。如果已定義，pgactivelink 會使用 last-update-wins 邏輯或您的自訂衝突處理常式來解決這些衝突。PRIMARY KEY 對於元組比對和衝突解決至關重要。對於沒有 PRIMARY KEY 的資料表，pgactivelink 會拒絕 UPDATE 操作，並顯示下列錯誤：

`Cannot run UPDATE or DELETE on table (tablename) because it does not have a primary key.`

### PRIMARY KEY 上的 UPDATE 衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict5"></a>

pgactive 在處理 PRIMARY KEY 更新時有限制。雖然您可以在 PRIMARY KEY 上執行 UPDATE 操作，但 pgactive 無法針對這些操作使用 last-update-wins 邏輯自動解決衝突。您必須確保 PRIMARY KEY 更新不會與現有值衝突。如果在 PRIMARY KEY 更新期間發生衝突，它們會成為需要您手動介入的分歧衝突。如需處理這些情況的詳細資訊，請參閱 [分歧衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict14)。

### 違反多個 UNIQUE 限制條件的 UPDATE
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict6"></a>

當傳入 UPDATE 違反多個 UNIQUE 限制條件或 PRIMARY KEY 值時，pgactivelink 無法套用 last-update-wins 衝突解決方法。此行為類似於違反多個限制條件的 INSERT 操作。這些情況會產生需要您手動介入的分歧衝突。如需詳細資訊，請參閱[分歧衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict14)。

### UPDATE/DELETE 衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict7"></a>

當一個節點對資料列進行 UPDATE 操作，而另一個節點同時對資料列進行 DELETE 操作時，就會發生此衝突。在此情況下，重新執行時會發生 UPDATE/DELETE 衝突。解決方法是捨棄 DELETE 之後到達的任何 UPDATE，除非您的自訂衝突處理常式另有指定。

pgactivelink 需要 PRIMARY KEY 以比對元組並解決衝突。對於沒有 PRIMARY KEY 的資料表，它會拒絕 DELETE 操作，並顯示下列錯誤：

`Cannot run UPDATE or DELETE on table (tablename) because it does not have a primary key.`

**注意**  
pgactivelink 無法區分 UPDATE/DELETE 和 INSERT/UPDATE 衝突。在這兩種情況下，UPDATE 都會影響不存在的資料列。由於非同步複寫和節點之間缺少重新執行順序，pgactivelink 無法判斷 UPDATE 是用於新資料列 (尚未收到 INSERT) 或刪除的資料列。在這兩種情況下，pgactivelink 都會捨棄 UPDATE。

### INSERT/UPDATE 衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict8"></a>

此衝突可能發生在多節點環境中。當一個節點針對資料列進行 INSERT 操作、第二個節點進行 UPDATE 操作，以及第三個節點在原始 INSERT 之前收到 UPDATE 時，就會發生這種情況。根據預設，除非您的自訂衝突觸發條件另有指定，否則 pgactivelink 會透過捨棄 UPDATE 來解決這些衝突。請注意，此解決方法可能會導致節點之間的資料不一致。如需類似案例及其處理方式的詳細資訊，請參閱 [UPDATE/DELETE 衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict7)。

### DELETE/DELETE 衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict9"></a>

當兩個不同的節點同時刪除相同的元組時，就會發生此衝突。pgactivelink 會將這些衝突視為無害，因為這兩個 DELETE 操作都有相同的最終結果。在此案例中，pgactivelink 會安全地忽略其中一個 DELETE 操作，而不會影響資料一致性。

### 外部索引鍵限制條件衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict10"></a>

FOREIGN KEY 限制條件可能會在將遠端交易套用至現有本機資料時造成衝突。當交易套用的順序與原始節點上的邏輯順序不同時，通常會發生這些衝突。

根據預設，pgactive 會將 session\$1replication\$1role 的變更套用為 `replica`，這會在複寫期間略過外部索引鍵檢查。在主動-主動組態中，這可能會導致外部索引鍵違規。大多數違規都是暫時性的，一旦複寫追上進度就會解決。不過，由於 pgactive 不支援跨節點資料列鎖定，因此可能會發生外部索引鍵懸置。

這是分區容限非同步主動-主動系統的固有行為。例如，節點 A 可能會插入新的子資料列，而節點 B 在此同時刪除其父資料列。系統無法防止跨節點進行此類並行修改。

若要將外部索引鍵衝突降至最低，建議您執行下列動作：
+ 將外部索引鍵關係限制在密切相關的實體。
+ 盡可能從單一節點修改相關實體。
+ 選擇很少需要修改的實體。
+ 實作應用程式層級並行控制以進行修改。

### 排除限制條件衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict11"></a>

 pgactive 連結不支援排除限制條件，並限制其建立。

**注意**  
如果您將現有的獨立資料庫轉換為 pgactivelink 資料庫，請手動捨棄所有排除限制條件。

在分散式非同步系統中，無法保證沒有任何一組資料列違反限制條件。這是因為不同節點上的所有交易都完全隔離。排除限制條件可能會導致重新執行死鎖，其中由於違反排除限制條件，重新執行無法從任何節點進展到另一個節點。

如果您強制 pgactive 連結建立排除限制條件，或在將獨立資料庫轉換為 pgactive 連結時未捨棄現有限制條件，複寫可能會中斷。若要還原複寫進度，請移除或更改與傳入遠端元組衝突的本機元組，以便套用遠端交易。

### 全域資料衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict12"></a>

使用 pgactivelink 時，如果節點具有不同的全域 PostgreSQL 全系統資料 (例如角色)，可能會發生衝突。這些衝突可能會導致操作 (主要是 DDL) 在一個節點上成功並遞交，但無法套用至其他節點。

如果使用者存在於一個節點，但不存在於另一個節點，則可能會發生複寫問題：
+ Node1 有名為 `fred` 的使用者，但 Node2 上不存在此使用者
+ 當 `fred` 在 Node1 上建立資料表時，資料表會以具備擁有者身分的 `fred` 進行複寫
+ 當此 DDL 命令套用至 Node2 時會失敗，因為使用者 `fred` 不存在
+ 此失敗會在 Node2 上的 PostgreSQL 日誌中產生錯誤，並讓 `pgactive.pgactive_stats.nr_rollbacks` 計數器增量

**解決方案：**在 Node2 上建立使用者 `fred`。使用者不需要相同的許可，但必須同時存在於兩個節點上。

如果資料表存在於一個節點，但不存在於另一個節點，資料修改操作將會失敗：
+ Node1 具有名為 `foo` 的資料表，該資料表不存在於 Node2
+ 複寫至 Node2 時，Node1 上 `foo` 資料表上的任何 DML 操作都會失敗

**解決方案：**在 Node2 上使用相同結構建立資料表 `foo`。

**注意**  
pgactivelink 目前不會複寫 CREATE USER 命令或 DDL 操作。DDL 複寫計畫用於未來版本。

### 鎖定衝突和死鎖中止
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict13"></a>

由於 pgactive 套用程序的運作方式與一般使用者工作階段類似，因此會遵循標準資料列和資料表鎖定規則。這可能會導致 pgactivelink 套用程序等待使用者交易或其他套用程序所保留的鎖定。

下列類型的鎖定可能會影響套用程序：
+ 依使用者工作階段的明確資料表層級鎖定 (LOCK TABLE ...)
+ 依使用者工作階段的明確資料列層級鎖定 (SELECT ... FOR UPDATE/FOR SHARE)
+ 從外部索引鍵鎖定
+ 從本機活動或從其他伺服器套用，由於資料列 UPDATE、INSERT 或 DELETE 的隱含鎖定

死鎖可能在以下項目之間發生：
+ pgactivelink 套用程序和使用者交易
+ 兩個套用程序

發生死鎖時，PostgreSQL 的死鎖偵測器會終止其中一個問題交易。如果 pgactivelink 套用工作者的程序已終止，則會自動重試，且通常會成功。

**注意**  
這些問題是暫時性的，通常不需要管理員介入。如果閒置使用者工作階段上的鎖定封鎖套用程序一段時間，您可以終止使用者工作階段以繼續複寫。這種情況類似於當使用者保留會影響另一個使用者工作階段的長鎖定時。
若要識別鎖定相關重新執行延遲，請在 PostgreSQL 中啟用 `log_lock_waits` 設施。

### 分歧衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict14"></a>

當節點之間應該相同的資料意外不同時，就會發生分歧衝突。雖然不應發生這些衝突，但無法在目前的實作中可靠地防止所有衝突。

**注意**  
 如果另一個節點在所有節點處理變更之前變更相同資料列的索引鍵，修改資料列的 PRIMARY KEY 可能會導致分歧衝突。避免變更主索引鍵，或將變更限制在一個指定的節點。如需詳細資訊，請參閱[PRIMARY KEY 上的 UPDATE 衝突](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict5)。

涉及資料列資料的分歧衝突通常需要管理員介入。若要解決這些衝突，您必須手動調整一個節點上的資料以符合另一個節點，同時使用 `pgactive.pgactive_do_not_replicate` 暫時停用複寫。當您依照文件記錄使用 pgactive，並避免將設定或函數標記為不安全時，不應發生這些衝突。

 身為管理員，您必須手動解決這些衝突。根據衝突類型，您需要使用進階選項，例如 `pgactive.pgactive_do_not_replicate`。請謹慎使用這些選項，因為不當使用可能會使情況惡化。由於各種可能的衝突，我們無法提供通用的解決方法指示。

當不同節點之間應該相同的資料意外不同時，就會發生分歧衝突。雖然不應發生這些衝突，但無法在目前的實作中可靠地防止所有此類衝突。

## 避免或容忍衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.avoidconflicts"></a>

 在大多數情況下，您可以使用適當的應用程式設計來避免衝突，或讓您的應用程式能夠容忍衝突。

 只有在多個節點上同時發生操作時，才會發生衝突。若要避免衝突：
+ 僅寫入一個節點
+ 寫入每個節點上的獨立資料庫子集 (例如，為每個節點指派個別結構描述)

對於 INSERT 與 INSERT 衝突，請使用全域序列來完全防止衝突。

 如果您的使用案例無法接受衝突，請考慮在應用程式層級實作分散式鎖定。最佳方法通常是設計您的應用程式以使用 pgactive 的衝突解決機制，而不是嘗試防止所有衝突。如需詳細資訊，請參閱[衝突類型](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflicttypes)。

## 衝突記錄
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflictlogging"></a>

pgactivelink 會在 `pgactive.pgactive_conflict_history` 資料表中記錄衝突事件，協助您診斷和處理主動-主動衝突。只有在您將 `pgactive.log_conflicts_to_table` 設定為 true 時，才會將衝突記錄到此資料表。當 log\$1min\$1messages 設定為 `LOG` 或 `lower` 時，無論 `pgactive.log_conflicts_to_table` 設定為何，pgactive 延伸模組也會將衝突記錄到 PostgreSQL 日誌檔案。

 使用衝突歷史記錄資料表：
+ 測量應用程式產生衝突的頻率
+ 識別衝突發生的位置
+ 改善您的應用程式以降低衝突率
+ 偵測衝突解決方法未產生所需結果的情況
+ 判斷您需要使用者定義的衝突觸發條件或應用程式設計變更的位置

 對於資料列衝突，您可以選擇性地記錄資料列值。這是由 `pgactive.log_conflicts_to_table` 設定所控制。請注意：
+ 這是全域全資料庫選項
+ 無法對資料列值記錄進行每個資料表控制
+ 欄位號碼、陣列元素或欄位長度未套用任何限制
+ 如果您使用可能觸發衝突的多 MB 資料列，則不建議啟用此功能

 由於衝突歷史記錄資料表包含資料庫中每個資料表的資料 (每個資料庫可能有不同的結構描述)，因此記錄的資料列值會儲存為 JSON 欄位。JSON 是使用 `row_to_json` 建立的，類似於直接從 SQL 呼叫它。PostgreSQL 不提供 `json_to_row` 函數，因此您需要資料表特定的程式碼 (PL/pgSQL、PL/Python、PL/Perl 等)，才能從記錄的 JSON 重建複合類型元組。

**注意**  
使用者定義衝突的支援會規劃為未來的延伸模組功能。

# 了解 pgactive 結構描述
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.schema"></a>

pgactive 結構描述會管理 RDS for PostgreSQL 中的主動-主動複寫。此結構描述包含儲存複寫組態和狀態資訊的資料表。

**注意**  
pgactive 結構描述正在演進，可能會有所變更。請勿直接修改這些資料表中的資料。

pgactive 結構描述中的索引鍵資料表包括：
+ `pgactive_nodes` – 儲存主動-主動複寫群組中節點的相關資訊。
+ `pgactive_connections` – 儲存每個節點的連線詳細資訊。

## pgactive\$1nodes
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.schema.nodes"></a>

pgactive\$1nodes 會儲存參與主動-主動複寫群組之節點的相關資訊。


| 資料行 | Type | 定序 | Nullable | 預設 | 
| --- | --- | --- | --- | --- | 
| node\$1sysid | text | – | 非 NULL | – | 
| node\$1timeline | oid | – | 非 NULL | – | 
| node\$1dboid | oid | – | 非 NULL | – | 
| node\$1status | char | – | 非 NULL | – | 
| node\$1name | text | – | 非 NULL | – | 
| node\$1dsn | text | – | 非 NULL | – | 
| node\$1init\$1from\$1dsn | text | – | 非 NULL | – | 
| node\$1read\$1only | boolean | – | – | false | 
| node\$1seq\$1id | smallint | – | 非 NULL | – | 

**node\$1sysid**  
節點的唯一 ID，在 `pgactive_create_group` 或 `pgactive_join_group` 期間產生

**node\$1status**  
節點的整備程度：  
+ **b** - 開始設定
+ **i** - 初始化
+ **c** - 追趕
+ **o** - 建立傳出插槽
+ **r** - 就緒
+ **k** - 已終止
此資料行不會指出節點是否已連線或中斷連線。

**node\$1name**  
使用者提供的唯一節點名稱。

**node\$1dsn**  
連線字串或使用者映射名稱

**node\$1init\$1from\$1dsn**  
建立此節點的 DSN。

## pgactive\$1connection
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.schema.connection"></a>

pgactive\$1connections 會儲存每個節點的連線詳細資訊。


| 資料行 | Type | 定序 | Nullable | 預設 | 
| --- | --- | --- | --- | --- | 
| conn\$1sysid | text | 無 | 非 NULL | 無 | 
| conn\$1timeline | oid | 無 | 非 NULL | 無 | 
| conn\$1dboid | oid | 無 | 非 NULL | 無 | 
| conn\$1dsn | text | 無 | 非 NULL | 無 | 
| conn\$1apply\$1delay | integer | 無 | 無 | 無 | 
| conn\$1replication\$1sets | text | 無 | 無 | 無 | 

conn\$1sysid  
此項目所參考節點的節點識別符。

conn\$1dsn  
與 pgactive.pgactive\$1nodes `node_dsn` 相同。

conn\$1apply\$1delay  
如果設定，在從遠端節點套用每個交易之前，要等待的毫秒數。主要用於偵錯。如果為 null，則套用全域預設值。

## 使用複寫集
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.replication"></a>

複寫集會決定要從複寫操作中包含或排除哪些資料表。根據預設，除非您使用下列函數另外指定，否則會複寫所有資料表：
+ `pgactive_exclude_table_replication_set()` - 從複寫中排除指定的資料表
+ `pgactive_include_table_replication_set()` - 在複寫中包含指定的資料表

**注意**  
設定複寫集之前，請考慮下列事項：  
您只能在執行 `pgactive_create_group()` 之後但在 `pgactive_join_group()` 之前設定資料表包含或排除。
使用 `pgactive_exclude_table_replication_set()` 之後，您就無法使用 `pgactive_include_table_replication_set()`。
使用 `pgactive_include_table_replication_set()` 之後，您就無法使用 `pgactive_exclude_table_replication_set()`。

系統會根據您的初始組態，以不同的方式處理新建立的資料表：
+ 如果您排除資料表：在 `pgactive_join_group()` 之後建立的任何新資料表都會自動包含在複寫中
+ 如果您包含資料表：在 `pgactive_join_group()` 之後建立的任何新資料表都會自動從複寫中排除。

若要檢視特定資料表的複寫集組態，請使用 `pgactive.pgactive_get_table_replication_sets()` 函數。

# pgactive 函數參考
<a name="pgactive-functions-reference"></a>

以下列出 pgactive 函數及其參數、傳回值，和協助您有效加以使用的實務使用須知：

## get\$1last\$1applied\$1xact\$1info
<a name="get-last-applied-xact-info"></a>

擷取指定節點的上次套用交易資訊。

**Arguments (引數)**  
+ sysid (文字) - 時間軸 OID
+ dboid (OID)

**傳回類型**  
會記錄下列項目：  
+ last\$1applied\$1xact\$1id (OID)
+ last\$1applied\$1xact\$1committs (含時區的時間戳記)
+ last\$1applied\$1xact\$1at (含時區的時間戳記)

**使用須知**  
使用此函數可擷取指定節點的上次套用交易資訊。

## pgactive\$1apply\$1pause
<a name="pgactive-apply-pause"></a>

暫停複寫套用程序。

**Arguments (引數)**  
無

**傳回類型**  
boolean

**使用須知**  
呼叫此函數可暫停複寫套用程序。

## pgactive\$1apply\$1resume
<a name="pgactive-apply-resume"></a>

繼續複寫套用程序。

**Arguments (引數)**  
無

**傳回類型**  
void

**使用須知**  
呼叫此函數可繼續複寫套用程序。

## pgactive\$1is\$1apply\$1paused
<a name="pgactive-is-apply-paused"></a>

檢查複寫目前是否暫停。

**Arguments (引數)**  
無

**傳回類型**  
boolean

**使用須知**  
使用此函數可檢查複寫套用目前是否暫停。

## pgactive\$1create\$1group
<a name="pgactive-create-group"></a>

藉由將獨立資料庫轉換為初始節點，來建立 pgactive 群組。



**Arguments (引數)**  
+ node\$1name (文字)
+ node\$1dsn (文字)
+ apply\$1delay integer DEFAULT NULL::integer - replication\$1sets text[] DEFAULT ARRAY[‘default’::text]

**傳回類型**  
void

**使用須知**  
藉由將獨立資料庫轉換為初始節點，來建立 pgactive 群組。此函數會在節點轉換為 pgactive 節點之前執行健全性檢查。使用此函數之前，請確定 PostgreSQL 叢集有足夠的 `max_worker_processes` 可支援 pgactive 背景工作者。

## pgactive\$1detach\$1nodes
<a name="pgactive-detach-nodes"></a>

從 pgactive 群組中移除指定的節點。

**Arguments (引數)**  
+ p\$1nodes (text[])

**傳回類型**  
void

**使用須知**  
使用此函數可從 pgactive 群組中移除指定的節點。

## pgactive\$1exclude\$1table\$1replication\$1set
<a name="pgactive-exclude-table-replication-set"></a>

將特定資料表排除於複寫外。

**Arguments (引數)**  
+ p\$1relation (regclass)

**傳回類型**  
void

**使用須知**  
使用此函數可將特定資料表排除於複寫外。

## pgactive\$1get\$1replication\$1lag\$1info
<a name="pgactive-get-replication-lag-info"></a>

擷取詳細的複寫延遲資訊，包括節點詳細資訊、WAL 狀態和 LSN 值。

**Arguments (引數)**  
無

**傳回類型**  
SETOF 記錄 - node\$1name text - node\$1sysid text - application\$1name text - slot\$1name text - active boolean - active\$1pid integer - pending\$1wal\$1decoding bigint - 在寄件者節點上解碼的 WAL 約略大小 (位元組) - pending\$1wal\$1to\$1apply bigint - 要在接收節點上套用的 WAL 約略大小 (位元組) - restart\$1lsn pg\$1lsn - confirmed\$1flush\$1lsn pg\$1lsn - sent\$1lsn pg\$1lsn - write\$1lsn pg\$1lsn - flush\$1lsn pg\$1lsn - replay\$1lsn pg\$1lsn

**使用須知**  
呼叫此函數可擷取複寫延遲資訊，包括節點詳細資訊、WAL 狀態和 LSN 值。

## pgactive\$1get\$1stats
<a name="pgactive-get-stats"></a>

擷取 pgactive 複寫統計資料。

**Arguments (引數)**  
無

**傳回類型**  
SETOF 記錄 - rep\$1node\$1id oid - rilocalid oid - riremoteid text - nr\$1commit bigint - nr\$1rollback bigint - nr\$1insert bigint - nr\$1insert\$1conflict bigint - nr\$1update bigint - nr\$1update\$1conflict bigint - nr\$1delete bigint - nr\$1delete\$1conflict bigint - nr\$1disconnect bigint

**使用須知**  
使用此函數可擷取 pgactive 複寫統計資料。

## pgactive\$1get\$1table\$1replication\$1sets
<a name="pgactive-get-table-replication-sets"></a>

取得特定關係的複寫集組態。

**Arguments (引數)**  
+ relation (regclass)

**傳回類型**  
SETOF 記錄

**使用須知**  
呼叫此函數可取得特定關係的複寫集組態。

## pgactive\$1include\$1table\$1replication\$1set
<a name="pgactive-include-table-replication-set"></a>

在複寫中包含特定資料表。

**Arguments (引數)**  
+ p\$1relation (regclass)

**傳回類型**  
void

**使用須知**  
使用此函數可在複寫中包含特定資料表。

## pgactive\$1join\$1group
<a name="pgactive-join-group"></a>

將節點新增至現有的 pgactive 群組。

**Arguments (引數)**  
+ node\$1name (文字)
+ node\$1dsn (文字)
+ join\$1using\$1dsn (文字)
+ apply\$1delay (整數，選用)
+ replication\$1sets (text[]，預設值：['default'])
+ bypass\$1collation\$1check (布林值，預設值：false)
+ bypass\$1node\$1identifier\$1creation (布林值，預設值：false)
+ bypass\$1user\$1tables\$1check (布林值，預設值：false)

**傳回類型**  
void

**使用須知**  
呼叫此函數，可將節點新增至現有的 pgactive 群組。請確定您的 PostgreSQL 叢集有足夠的 max\$1worker\$1processes 供 pgactive 背景工作者使用。

## pgactive\$1remove
<a name="pgactive-remove"></a>

從本機節點中移除所有 pgactive 元件。

**Arguments (引數)**  
+ force (布林值，預設值：false)

**傳回類型**  
void

**使用須知**  
呼叫此函數，從本機節點中移除所有 pgactive 元件。

## pgactive\$1snowflake\$1id\$1nextval
<a name="pgactive-snowflake-id-nextval"></a>

產生節點特定的唯一序列值。

**Arguments (引數)**  
+ regclass

**傳回類型**  
bigint

**使用須知**  
使用此函數可產生節點特定的唯一序列值。

## pgactive\$1update\$1node\$1conninfo
<a name="pgactive-update-node-conninfo"></a>

更新 pgactive 節點的連線資訊。

**Arguments (引數)**  
+ node\$1name\$1to\$1update (文字)
+ node\$1dsn\$1to\$1update (文字)

**傳回類型**  
void

**使用須知**  
使用此函數可更新 pgactive 節點的連線資訊。

## pgactive\$1wait\$1for\$1node\$1ready
<a name="pgactive-wait-for-node-ready"></a>

監控群組建立或加入操作的進度。

**Arguments (引數)**  
+ 逾時 (整數，預設值：0)
+ progress\$1interval (整數，預設值：60)

**傳回類型**  
void

**使用須知**  
呼叫此函數可監控群組建立或加入操作的進度。

# 處理主動-主動式複寫中的衝突
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-conflicts"></a>

`pgactive` 延伸模組是在每個資料庫上運作，而不是每個叢集。使用 `pgactive` 的每個資料庫執行個體都是獨立的執行個體，可接受任何來源的資料變更。將變更傳送至資料庫執行個體時，PostgreSQL 會在本機上遞交該變更，然後使用 `pgactive` 以非同步方式將變更複寫到其他資料庫執行個體。當兩個 PostgreSQL 資料庫執行個體幾乎同時更新相同的記錄時，可能會發生衝突。

`pgactive` 延伸模組提供了衝突偵測和自動解決的機制。它會追蹤交易在兩個資料庫執行個體上得到認可的時間戳記，並自動套用具有最新時間戳記的變更。`pgactive` 延伸模組也會記錄 `pgactive.pgactive_conflict_history` 資料表中發生的衝突。

`pgactive.pgactive_conflict_history` 會持續成長。您可能想要定義清除政策。這可以透過定期刪除一些記錄或定義此關係的分割結構描述 (以及稍後分離、捨棄、截斷感興趣的分割區) 來完成。若要定期實作清除政策，其中一個選項是使用 `pg_cron` 延伸模組。請參閱 `pg_cron` 歷史記錄資料表範例的下列資訊，[使用 PostgreSQL pg\$1cron 延伸模組排程維護](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/PostgreSQL_pg_cron.html)。

# 處理主動-主動式複寫中的序列
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-sequences"></a>

具有 `pgactive` 延伸模組的 RDS for PostgreSQL 資料庫執行個體使用兩種不同的序列機制來產生唯一值。

**全域序列**  
若要使用全域序列，請使用 `CREATE SEQUENCE` 陳述式建立本機序列。不要使用 `usingnextval(seqname)`，而是使用 `pgactive.pgactive_snowflake_id_nextval(seqname)` 來取得序列中的下一個唯一值。

下列範例會建立全域序列：

```
app=> CREATE TABLE gstest (
      id bigint primary key,
      parrot text
    );
```

```
app=>CREATE SEQUENCE gstest_id_seq OWNED BY gstest.id;
```

```
app=> ALTER TABLE gstest \
      ALTER COLUMN id SET DEFAULT \
      pgactive.pgactive_snowflake_id_nextval('gstest_id_seq');
```

**分割序列**  
在拆分步驟或分割序列中，每個節點上會使用標準 PostgreSQL 序列。每個序列會以相同的量遞增，並從不同的偏移量開始。例如，若是步進 100，節點 1 會產生序列為 101、201、301，依此類推，而節點 2 會產生序列為 102、202、302，依此類推。即使節點無法長時間通訊，此結構仍能正常運作，但是設計人員必須在建立結構描述時指定最大節點數，並且需要每個節點的組態。若發生錯誤，便容易導致序列重疊。

透過在節點上建立所需的序列來對 `pgactive` 設定此方法相對較為簡單，如下所示：

```
CREATE TABLE some_table (generated_value bigint primary key);
```

```
app=> CREATE SEQUENCE some_seq INCREMENT 100 OWNED BY some_table.generated_value;
```

```
app=> ALTER TABLE some_table ALTER COLUMN generated_value SET DEFAULT nextval('some_seq');
```

然後在每個節點上呼叫，以提供不同的偏移量起始值，如下所示。

```
app=>
-- On node 1
SELECT setval('some_seq', 1);

-- On node 2
SELECT setval('some_seq', 2);
```

# 使用 pg\$1repack 擴充功能減少資料表和索引膨脹
<a name="Appendix.PostgreSQL.CommonDBATasks.pg_repack"></a>

您可以使用 `pg_repack` 延伸模組，移除資料表和索引膨脹情形，做為 `VACUUM FULL` 的替代項目。RDS for PostgreSQL 9.6.3 及更新版本支援此擴充功能。如需 `pg_repack` 延伸模組和完整資料表重新封裝的詳細資訊，請參閱 [GitHub 專案文件](https://reorg.github.io/pg_repack/)。

與 `VACUUM FULL` 不同，在下列情況下，`pg_repack` 延伸模組在資料表重建操作期間只需要短暫的專屬鎖定 (AccessExclusiveLock)：
+ 初始建立日誌資料表 – 建立日誌資料表以記錄資料初始複製期間發生的變更，如下列範例所示：

  ```
  postgres=>\dt+ repack.log_*
  List of relations
  -[ RECORD 1 ]-+----------
  Schema        | repack
  Name          | log_16490
  Type          | table
  Owner         | postgres
  Persistence   | permanent
  Access method | heap
  Size          | 65 MB
  Description   |
  ```
+ 最終交換放置階段。

對於其他重建操作，只需要 `ACCESS SHARE` 鎖定原始資料表，即可將資料列從原始資料表複製到新資料表。這有助於 INSERT、UPDATE 和 DELETE 操作照常繼續進行。

## 建議
<a name="Appendix.PostgreSQL.CommonDBATasks.pg_repack.Recommen"></a>

當您使用 `pg_repack` 延伸模組從資料表和索引中移除膨脹時，適用下列建議：
+ 在非上班時間或維護時段執行重新封裝，將對其他資料庫活動效能的影響降至最低。
+ 在重建活動期間密切監控封鎖工作階段，並確保原始資料表上沒有可能封鎖 `pg_repack` 的活動，特別是在最終交換放置階段需要對原始資料表進行專屬鎖定時。如需詳細資訊，請參閱[識別封鎖查詢的項目](https://repost.aws/knowledge-center/rds-aurora-postgresql-query-blocked)。

  當您看到封鎖工作階段時，您可以在仔細考慮後使用下列命令將其終止。這有助於繼續 `pg_repack` 以完成重建：

  ```
  SELECT pg_terminate_backend(pid);
  ```
+ 在交易速率非常高的系統上套用 `pg_repack's` 日誌資料表中累積的變更時，套用程序可能無法跟上變更速率。在這種情況下，`pg_repack` 無法完成套用程序。如需詳細資訊，請參閱[在重新封裝期間監控新資料表](#Appendix.PostgreSQL.CommonDBATasks.pg_repack.Monitoring)。如果索引嚴重膨脹，替代解決方案是執行僅限索引重新封裝。這也有助於 VACUUM 的索引清除週期更快完成。

  您可以使用 PostgreSQL 第 12 版的手動 VACUUM 以略過索引清除階段，並在 PostgreSQL 第 14 版的緊急自動清空期間自動略過。這有助於 VACUUM 更快速地完成，無需移除索引膨脹，而且僅適用於防止包圍 VACUUM 等緊急狀況。如需詳細資訊，請參閱《Amazon Aurora 使用者指南》中的[避免在索引中膨脹](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.diag-table-ind-bloat.html#AuroraPostgreSQL.diag-table-ind-bloat.AvoidinginIndexes)。

## 先決條件
<a name="Appendix.PostgreSQL.CommonDBATasks.pg_repack.Prereq"></a>
+ 資料表必須具有 PRIMARY KEY 或非 null UNIQUE 限制條件。
+ 用戶端和伺服器的延伸模組版本必須相同。
+ 確保 RDS 執行個體具有比沒有膨脹的資料表大小總計更多的 `FreeStorageSpace`。例如，請考慮資料表的大小總計，包括 TOAST 和索引為 2TB，資料表中的膨脹總計為 1TB。必要的 `FreeStorageSpace` 必須大於下列計算傳回的值：

   `2TB (Table size)` - `1TB (Table bloat)` = `1TB`

  您可以使用下列查詢來檢查資料表的大小總計，並使用 `pgstattuple` 衍生膨脹。如需詳細資訊，請參閱《Amazon Aurora 使用者指南》中的[診斷資料表和索引膨脹](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.diag-table-ind-bloat.html) 

  ```
  SELECT pg_size_pretty(pg_total_relation_size('table_name')) AS total_table_size;
  ```

  此空間會在活動完成後回收。
+ 確保 RDS 執行個體有足夠的運算和 IO 容量來處理重新封裝操作。您可以考慮向上擴展執行個體類別，以獲得最佳效能平衡。

**使用 `pg_repack` 延伸模組**

1. 執行以下命令，在 RDS for PostgreSQL 資料庫執行個體上安裝 `pg_repack` 擴充功能。

   ```
   CREATE EXTENSION pg_repack;
   ```

1. 執行下列命令授予 `pg_repack` 所建立暫存日誌資料表的寫入存取權。

   ```
   ALTER DEFAULT PRIVILEGES IN SCHEMA repack GRANT INSERT ON TABLES TO PUBLIC;
   ALTER DEFAULT PRIVILEGES IN SCHEMA repack GRANT USAGE, SELECT ON SEQUENCES TO PUBLIC;
   ```

1. 使用 `pg_repack` 用戶端公用程式來連線至資料庫。使用具有 `rds_superuser` 權限的帳戶。舉例來說，假設 `rds_test` 角色具有 `rds_superuser` 權限。下列語法會針對完整資料表執行 `pg_repack`，包括 `postgres` 資料庫中的所有資料表索引。

   ```
   pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -U rds_test -k postgres
   ```
**注意**  
您必須使用 -k 選項進行連線。不支援 -a 選項。

   來自 `pg_repack` 用戶端的回應會提供資料庫執行個體上已重新封裝之資料表的資訊。

   ```
   INFO: repacking table "pgbench_tellers"
   INFO: repacking table "pgbench_accounts"
   INFO: repacking table "pgbench_branches"
   ```

1. 下列語法會重新封裝單一資料表 `orders`，包括 `postgres` 資料庫中的索引。

   ```
   pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -U rds_test --table orders -k postgres
   ```

   下列語法只會重新封裝 `postgres` 資料庫中 `orders` 資料表的索引。

   ```
   pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -U rds_test --table orders --only-indexes -k postgres
   ```

## 在重新封裝期間監控新資料表
<a name="Appendix.PostgreSQL.CommonDBATasks.pg_repack.Monitoring"></a>
+ 資料庫的大小會增加資料表的大小總計減去膨脹，直到重新封裝的交換放置階段為止。您可以監控資料庫大小的成長速率、計算重新封裝的速度，以及大概預估完成初始資料傳輸所需的時間。

  例如，將資料表的大小總計視為 2TB、將資料庫的大小視為 4TB，並將資料表中的膨脹總計視為 1TB。重新封裝操作結束時，計算傳回的資料庫大小總計值如下：

   `2TB (Table size)` \$1 `4 TB (Database size)` - `1TB (Table bloat)` = `5TB`

  您可以透過取樣兩個時間點之間的成長率 (以位元組為單位)，大致估計重新封裝操作的速度。如果成長率為每分鐘 1GB，則可能需要 1000 分鐘或 16.6 小時左右才能完成初始資料表建置操作。除了初始資料表建置之外，`pg_repack` 也需要套用累積的變更。所需的時間取決於套用持續變更以及累積變更的速率。
**注意**  
您可以使用 `pgstattuple` 延伸模組來計算資料表中的膨脹。如需更多詳細資訊，請參閱 [pgstattuple](https://www.postgresql.org/docs/current/pgstattuple.html)。
+ `pg_repack's` 日誌資料表中的資料列數目，在重新封裝結構描述下，代表待定在初始載入後套用至新資料表的變更量。

  您可以在 `pg_stat_all_tables` 中檢查 `pg_repack's` 日誌資料表，以監控套用至新資料表的變更。`pg_stat_all_tables.n_live_tup` 表示待定套用至新資料表的記錄數目。如需詳細資訊，請參閱 [pg\$1stat\$1all\$1tables](https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-ALL-TABLES-VIEW)。

  ```
  postgres=>SELECT relname,n_live_tup FROM pg_stat_all_tables WHERE schemaname = 'repack' AND relname ILIKE '%log%';
          
  -[ RECORD 1 ]---------
  relname    | log_16490
  n_live_tup | 2000000
  ```
+ 您可以使用 `pg_stat_statements` 延伸模組來了解重新封裝操作中每個步驟所花費的時間。這有助於準備在生產環境中套用相同的重新封裝操作。您可以調整 `LIMIT` 子句以進一步擴展輸出。

  ```
  postgres=>SELECT
       SUBSTR(query, 1, 100) query,
       round((round(total_exec_time::numeric, 6) / 1000 / 60),4) total_exec_time_in_minutes
   FROM
       pg_stat_statements
   WHERE
       query ILIKE '%repack%'
   ORDER BY
       total_exec_time DESC LIMIT 5;
          
   query                                                                 | total_exec_time_in_minutes
  -----------------------------------------------------------------------+----------------------------
   CREATE UNIQUE INDEX index_16493 ON repack.table_16490 USING btree (a) |                     6.8627
   INSERT INTO repack.table_16490 SELECT a FROM ONLY public.t1           |                     6.4150
   SELECT repack.repack_apply($1, $2, $3, $4, $5, $6)                    |                     0.5395
   SELECT repack.repack_drop($1, $2)                                     |                     0.0004
   SELECT repack.repack_swap($1)                                         |                     0.0004
  (5 rows)
  ```

重新封裝完全是空間外的作業，因此原始資料表不會受到影響，而且我們預期不會有任何需要復原原始資料表的意外挑戰。如果重新封裝意外失敗，您必須檢查錯誤的原因並加以解決。

問題解決後，請在資料表所在的資料庫中捨棄並重新建立 `pg_repack` 延伸模組，然後重試 `pg_repack` 步驟。此外，運算資源的可用性和資料表的並行可存取性在重新封裝操作的及時完成中扮演了關鍵角色。

# 升級和使用 PLV8 擴充功能
<a name="PostgreSQL.Concepts.General.UpgradingPLv8"></a>

PLV8 是值得信賴的 JavaScript 語言擴充功能，適用於 PostgreSQL。您可用於存放的程序、觸發程序和可從 SQL 呼叫的其他程序性程式碼。所有目前版本的 PostgreSQL 都支援此語言擴充功能。

如果您使用 [PLV8](https://plv8.github.io/) 並將 PostgreSQL 升級至新的 PLV8 版本，即可立即利用新的擴充功能套件。執行下列步驟，同步目錄中繼資料與新版的 PLV8。這些步驟為選用，但強烈建議您完成步驟以避免中繼資料不符的警告。

升級程序會捨棄您現有的所有 PLV8 函數。因此，我們建議您在升級之前建立 RDS for PostgreSQL 資料庫執行個體的快照。如需詳細資訊，請參閱[為 Amazon RDS 的單一可用區域資料庫執行個體建立資料庫快照](USER_CreateSnapshot.md)。

**重要**  
從 PostgreSQL 第 18 版開始，Amazon RDS for PostgreSQL 將棄用 `plcoffee` 和 `plls` PostgreSQL 延伸模組。建議您在應用程式中停止使用 CoffeeScript 和 LiveScript，以確保您具有未來引擎版本升級的升級路徑。

**如何同步目錄中繼資料與新版 PLV8**

1. 確認您需要更新。若要執行此動作，請在已連接至執行個體的情況下，執行下列命令。

   ```
   SELECT * FROM pg_available_extensions WHERE name IN ('plv8','plls','plcoffee');
   ```

   如果結果包含一個已安裝之版本的值，而此版本的編號小於預設版本，則請繼續此程序來更新擴充功能套件。例如，下列結果集表示您應該更新。

   ```
   name    | default_version | installed_version |                     comment
   --------+-----------------+-------------------+--------------------------------------------------
   plls    | 2.1.0           | 1.5.3             | PL/LiveScript (v8) trusted procedural language
   plcoffee| 2.1.0           | 1.5.3             | PL/CoffeeScript (v8) trusted procedural language
   plv8    | 2.1.0           | 1.5.3             | PL/JavaScript (v8) trusted procedural language
   (3 rows)
   ```

1. 如果您尚未建立 RDS for PostgreSQL 資料庫執行個體的快照，請建立一個。建立快照時，您可以繼續執行下列步驟。

1. 取得資料庫執行個體中的 PLV8 函數計數，以驗證升級之後函數全部存在。例如，下列 SQL 查詢會傳回 PLV8、plcoffee 和 plls 中寫入的函數數目。

   ```
   SELECT proname, nspname, lanname 
   FROM pg_proc p, pg_language l, pg_namespace n
   WHERE p.prolang = l.oid
   AND n.oid = p.pronamespace
   AND lanname IN ('plv8','plcoffee','plls');
   ```

1. 使用 pg\$1dump 建立只含結構描述的傾印檔案。例如，在 `/tmp` 目錄中建立用戶端機器上的檔案。

   ```
   ./pg_dump -Fc --schema-only -U master postgres >/tmp/test.dmp
   ```

   此範例使用下列選項：
   + `-Fc` – 自訂格式
   + --schema-only – 僅傾印建立結構描述所需的命令 (我們案例中的函數)
   + `-U` – RDS 主要使用者名稱
   + `database` – 資料庫執行個體上的資料庫名稱

   如需有關 pg\$1dump 的詳細資訊，請參閱 PostgreSQL 文件中的 [pg\$1dump](https://www.postgresql.org/docs/current/static/app-pgdump.html )。

1. 擷取傾印檔案中存在的「CREATE FUNCTION」DDL 陳述式。下列範例使用 `grep` 命令擷取用於建立函數並儲存到檔案中的 DDL 陳述式。您將於後續步驟中使用此 ddl 來重新建立函數。

   ```
   ./pg_restore -l /tmp/test.dmp | grep FUNCTION > /tmp/function_list
   ```

   如需有關 pg\$1restore 的詳細資訊，請參閱 PostgreSQL 文件中的 [pg\$1restore](https://www.postgresql.org/docs/current/static/app-pgrestore.html)。

1. 捨棄函數和擴充功能。下列範例會捨棄任何以 PLV8 為基礎的物件。cascade 選項可確保捨棄任何相依物件。

   ```
   DROP EXTENSION plv8 CASCADE;
   ```

   如果 PostgreSQL 執行個體包含以 plcoffee 或 plls 為基礎的物件，請對這些擴充功能重複此步驟。

1. 建立擴充功能。下列範例會建立 plv8、plcoffee 和 plls 擴充功能。

   ```
   CREATE EXTENSION plv8;
   CREATE EXTENSION plcoffee;
   CREATE EXTENSION plls;
   ```

1. 使用傾印檔案和「驅動程式」檔案建立函數。

   下列範例會重新建立您先前擷取的函數。

   ```
   ./pg_restore -U master -d postgres -Fc -L /tmp/function_list /tmp/test.dmp
   ```

1. 使用以下查詢驗證是否已重新建立所有函數。

   ```
   SELECT * FROM pg_available_extensions WHERE name IN ('plv8','plls','plcoffee'); 
   ```

   PLV8 第 2 版會將以下額外的資料列新增至結果集：

   ```
       proname    |  nspname   | lanname
   ---------------+------------+----------
    plv8_version  | pg_catalog | plv8
   ```

# 使用 PL/Rust 以 Rust 語言撰寫 PostgreSQL 函數
<a name="PostgreSQL.Concepts.General.Using.PL_Rust"></a>

PL/Rust 是 PostgreSQL 的受信任 Rust 語言延伸模組。您可以將其用於預存程序、函數，以及可從 SQL 呼叫的其他程序性程式碼。下列版本提供 PL/Rust 語言延伸模組：
+ RDS for PostgreSQL 17.1 和更高的第 17 版
+ RDS for PostgreSQL 16.1 和更高的第 16 版
+ RDS for PostgreSQL 15.2-R2 及更高的 15 版本
+ RDS for PostgreSQL 14.9 及更高的 14 版本
+ RDS for PostgreSQL 13.12 及更高的 13 版本

如需詳細資訊，請參閱 GitHub 上的 [PL/Rust](https://github.com/tcdi/plrust#readme)。

**Topics**
+ [設定 PL/Rust](#PL_Rust-setting-up)
+ [使用 PL/Rust 建立函數](#PL_Rust-create-function)
+ [使用套件搭配 PL/Rust](#PL_Rust-crates)
+ [PL/Rust 限制](#PL_Rust-limitations)

## 設定 PL/Rust
<a name="PL_Rust-setting-up"></a>

若要在資料庫執行個體上安裝 plrust 延伸模組，請將 plrust 新增至與資料庫執行個體相關聯之資料庫參數群組中的 `shared_preload_libraries` 參數。安裝 plrust 延伸模組後，您可以建立函數。

若要修改 `shared_preload_libraries` 參數，您的資料庫執行個體必須與自訂參數群組相關聯。如需建立自訂資料庫參數群組的相關資訊，請參閱 [Amazon RDS 的參數群組](USER_WorkingWithParamGroups.md)。

您可以使用 AWS 管理主控台 或 安裝 plrust 擴充功能 AWS CLI。

下列步驟假設您的資料庫執行個體與自訂資料庫參數群組相關聯。

### 主控台
<a name="PL_Rust-setting-up.CON"></a>

**在 `shared_preload_libraries` 參數中安裝 plrust 延伸模組**

使用屬於 `rds_superuser` 群組 (角色) 成員的帳戶完成下列步驟。

1. 登入 AWS 管理主控台 ，並在 [https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/)：// 開啟 Amazon RDS 主控台。

1. 在導覽窗格中，選擇 **Databases** (資料庫)。

1. 選擇資料庫執行個體的名稱以顯示其詳細資訊。

1. 開啟資料庫執行個體的**組態**索引標籤，然後尋找資料庫執行個體參數群組連結。

1. 選擇連結以開啟與資料庫執行個體相關聯的自訂參數。

1. 在 **Parameters** (參數) 搜尋欄位中，輸入 `shared_pre` 以尋找 **`shared_preload_libraries`** 參數。

1. 選擇 **Edit parameters** (編輯參數) 以存取屬性值。

1. 在**值**欄位中，將 plrust 新增至清單。使用逗號區隔值清單中的項目。

1. 重新啟動資料庫執行個體，以便您對 `shared_preload_libraries` 參數的變更生效。初始重新啟動可能需要額外的時間才能完成。

1. 當執行個體可用時，請驗證 plrust 是否已初始化。使用 `psql` 連線至資料庫執行個體，然後執行下列命令。

   ```
   SHOW shared_preload_libraries;
   ```

   您的輸出應該類似以下內容：

   ```
   shared_preload_libraries 
   --------------------------
   rdsutils,plrust
   (1 row)
   ```

### AWS CLI
<a name="PL_Rust-setting-up-CLI"></a>

**在 shared\$1preload\$1libraries 參數中安裝 plrust 延伸模組**

使用屬於 `rds_superuser` 群組 (角色) 成員的帳戶完成下列步驟。

1. 使用 [modify-db-parameter-group](https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-parameter-group.html) AWS CLI 命令將 plrust 新增至 `shared_preload_libraries` 參數。

   ```
   aws rds modify-db-parameter-group \
      --db-parameter-group-name custom-param-group-name \
      --parameters "ParameterName=shared_preload_libraries,ParameterValue=plrust,ApplyMethod=pending-reboot" \
      --region aws-region
   ```

1. 使用 [reboot-db-instance](https://docs.aws.amazon.com/cli/latest/reference/rds/reboot-db-instance) AWS CLI 命令重新啟動資料庫執行個體並初始化 plrust 程式庫。初始重新啟動可能需要額外的時間才能完成。

   ```
   aws rds reboot-db-instance \
       --db-instance-identifier your-instance \
       --region aws-region
   ```

1. 當執行個體可用時，您可以驗證 plrust 是否已初始化。使用 `psql` 連線至資料庫執行個體，然後執行下列命令。

   ```
   SHOW shared_preload_libraries;
   ```

   您的輸出應該類似以下內容：

   ```
   shared_preload_libraries
   --------------------------
   rdsutils,plrust
   (1 row)
   ```

## 使用 PL/Rust 建立函數
<a name="PL_Rust-create-function"></a>

PL/Rust 會將函數編譯為動態程式庫、載入它，然後執行它。

以下 Rust 函數會從陣列中篩選出倍數。

```
postgres=> CREATE LANGUAGE plrust;
CREATE EXTENSION
```

```
CREATE OR REPLACE FUNCTION filter_multiples(a BIGINT[], multiple BIGINT) RETURNS BIGINT[]
    IMMUTABLE STRICT
    LANGUAGE PLRUST AS
$$
    Ok(Some(a.into_iter().filter(|x| x.unwrap() % multiple != 0).collect()))
$$;
        
WITH gen_values AS (
SELECT ARRAY(SELECT * FROM generate_series(1,100)) as arr)
SELECT filter_multiples(arr, 3)
from gen_values;
```

## 使用套件搭配 PL/Rust
<a name="PL_Rust-crates"></a>

在 RDS for PostgreSQL 16.3-R2 和更高版本、15.7-R2 和更高的第 15 版、14.12-R2 和更高的第 14 版，以及 13.15-R2 和更高的第 13 版中，PL/Rust 支援額外的壓縮容器格式：
+ `url` 
+ `regex` 
+ `serde` 
+ `serde_json` 

在 RDS for PostgreSQL 15.5-R2 和更高版本、14.10-R2 和更高的第 14 版、13.13-R2 和更高的第 13 版中，PL/Rust 支援兩個額外的壓縮容器格式：
+ `croaring-rs` 
+ `num-bigint` 

從 Amazon RDS for PostgreSQL 15.4、14.9 及 13.12 版開始，PL/Rust 支援下列壓縮容器格式：
+ `aes` 
+ `ctr` 
+ `rand` 

這些套件僅支援預設功能。新的 RDS for PostgreSQL 版本可能包含更新的套件版本，而且可能不再支援較舊的套件版本。

請遵循執行主要版本升級的最佳實務來進行測試，了解您的 PL/Rust 函數是否與新的主要版本相容。如需詳細資訊，請參閱部落格 [Best practices for upgrading Amazon RDS to major and minor versions of PostgreSQL](https://aws.amazon.com/blogs/database/best-practices-for-upgrading-amazon-rds-to-major-and-minor-versions-of-postgresql/) (將 Amazon RDS 升級至 PostgreSQL 的主要和次要版本的最佳實務)，以及《Amazon RDS 使用者指南》中的[升級 Amazon RDS 的 PostgreSQL 資料庫引擎](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.PostgreSQL.html)。

[使用相依性](https://tcdi.github.io/plrust/use-plrust.html#use-dependencies)中提供了建立 PL/Rust 函數時使用相依性的範例。

## PL/Rust 限制
<a name="PL_Rust-limitations"></a>

根據預設，資料庫使用者無法使用 PL/Rust。若要提供 PL/Rust 的存取權，請以具有 rds\$1superuser 權限的使用者身分連線，然後執行下列命令：

```
postgres=> GRANT USAGE ON LANGUAGE PLRUST TO user;
```

# 使用 PostGIS 擴充功能管理空間資料
<a name="Appendix.PostgreSQL.CommonDBATasks.PostGIS"></a>

PostGIS 是 PostgreSQL 的擴充功能，可用於儲存和管理空間資訊。若要進一步了解 PostGIS，請參閱 [PostGIS.net](https://postgis.net/)。

從 10.5 版開始，PostgreSQL 即支援 PostGIS 用於處理 Mapbox向量圖標資料的 libprotobuf 1.3.0 程式庫。

設定 PostGIS 擴充功能需要 `rds_superuser` 權限。我們建議您建立一使用者 (角色) 來管理 PostGIS 擴充功能及您的空間資料。PostGIS 擴充功能及其相關元件會為 PostgreSQL 新增數千個函數。若這對您的使用案例有意義，請考慮在其自己的結構描述中建立 PostGIS 擴充功能。下列範例會顯示如何在其自己的資料庫中安裝擴充功能，但這並非必要。

**Topics**
+ [步驟 1：建立使用者 (角色) 來管理 PostGIS 擴充功能](#Appendix.PostgreSQL.CommonDBATasks.PostGIS.Connect)
+ [步驟 2：載入 PostGIS 擴充功能](#Appendix.PostgreSQL.CommonDBATasks.PostGIS.LoadExtensions)
+ [步驟 3：轉移延伸模組結構描述的擁有權](#Appendix.PostgreSQL.CommonDBATasks.PostGIS.TransferOwnership)
+ [步驟 4：轉移 PostGIS 物件的擁有權](#Appendix.PostgreSQL.CommonDBATasks.PostGIS.TransferObjects)
+ [步驟 5：測試擴充功能](#Appendix.PostgreSQL.CommonDBATasks.PostGIS.Test)
+ [步驟 6：升級 PostGIS 擴充功能](#Appendix.PostgreSQL.CommonDBATasks.PostGIS.Update)
+ [PostGIS 擴充功能版本](#CHAP_PostgreSQL.Extensions.PostGIS)
+ [將 PostGIS 2 升級到 PostGIS 3](#PostgreSQL.Extensions.PostGIS.versions.upgrading.2-to-3)

## 步驟 1：建立使用者 (角色) 來管理 PostGIS 擴充功能
<a name="Appendix.PostgreSQL.CommonDBATasks.PostGIS.Connect"></a>

首先，以具有 `rds_superuser` 權限的使用者身分連線至您的 RDS for PostgreSQL 資料庫執行個體。若您在設定執行個體時保留預設名稱，則以 `postgres` 身分連線：

```
psql --host=111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password
```

建立一個單獨的角色 (使用者) 來管理 PostGIS 擴充功能。

```
postgres=>  CREATE ROLE gis_admin LOGIN PASSWORD 'change_me';
CREATE ROLE
```

授予此角色 `rds_superuser` 權限，允許角色安裝擴充功能。

```
postgres=> GRANT rds_superuser TO gis_admin;
GRANT
```

建立用於 PostGIS 成品的資料庫：此為選擇性步驟。或者，您可以在 PostGIS 擴充功能的使用者資料庫中建立結構描述，但這也並非必要。

```
postgres=> CREATE DATABASE lab_gis;
CREATE DATABASE
```

授予 `gis_admin` 在 `lab_gis` 資料庫上的所有權限。

```
postgres=> GRANT ALL PRIVILEGES ON DATABASE lab_gis TO gis_admin;
GRANT
```

退出工作階段，並以 `gis_admin` 身分重新連線至您的 RDS for PostgreSQL 資料庫執行個體。

```
postgres=> psql --host=111122223333.aws-region.rds.amazonaws.com --port=5432 --username=gis_admin --password --dbname=lab_gis
Password for user gis_admin:...
lab_gis=>
```

按照後續步驟中的詳細說明，繼續設定擴充功能。

## 步驟 2：載入 PostGIS 擴充功能
<a name="Appendix.PostgreSQL.CommonDBATasks.PostGIS.LoadExtensions"></a>

PostGIS 擴充功能包含數個共同運作的相關擴充功能，以提供地理空間的功能。根據您的使用案例，可能不需要在此步驟中建立的所有擴充功能。

使用 `CREATE EXTENSION` 陳述式載入 PostGIS 擴充。

```
CREATE EXTENSION postgis;
CREATE EXTENSION
CREATE EXTENSION postgis_raster;
CREATE EXTENSION
CREATE EXTENSION fuzzystrmatch;
CREATE EXTENSION
CREATE EXTENSION postgis_tiger_geocoder;
CREATE EXTENSION
CREATE EXTENSION postgis_topology;
CREATE EXTENSION
CREATE EXTENSION address_standardizer_data_us;
CREATE EXTENSION
```

您可以執行下例中顯示的 SQL 查詢來確認結果，其中列出擴充功能及其擁有者。

```
SELECT n.nspname AS "Name",
  pg_catalog.pg_get_userbyid(n.nspowner) AS "Owner"
  FROM pg_catalog.pg_namespace n
  WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'
  ORDER BY 1;
List of schemas
     Name     |   Owner
--------------+-----------
 public       | postgres
 tiger        | rdsadmin
 tiger_data   | rdsadmin
 topology     | rdsadmin
(4 rows)
```

## 步驟 3：轉移延伸模組結構描述的擁有權
<a name="Appendix.PostgreSQL.CommonDBATasks.PostGIS.TransferOwnership"></a>

使用 ALTER SCHEMA 陳述式將結構描述的擁有權移轉至 `gis_admin` 角色。

```
ALTER SCHEMA tiger OWNER TO gis_admin;
ALTER SCHEMA
ALTER SCHEMA tiger_data OWNER TO gis_admin; 
ALTER SCHEMA
ALTER SCHEMA topology OWNER TO gis_admin;
ALTER SCHEMA
```

您可執行下列 SQL 查詢，來確認所有權變更。您也可以使用 `\dn` 中繼命令和 psql 命令列。

```
SELECT n.nspname AS "Name",
  pg_catalog.pg_get_userbyid(n.nspowner) AS "Owner"
  FROM pg_catalog.pg_namespace n
  WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'
  ORDER BY 1;

       List of schemas
     Name     |     Owner
--------------+---------------
 public       | postgres
 tiger        | gis_admin
 tiger_data   | gis_admin
 topology     | gis_admin
(4 rows)
```

## 步驟 4：轉移 PostGIS 物件的擁有權
<a name="Appendix.PostgreSQL.CommonDBATasks.PostGIS.TransferObjects"></a>

**注意**  
請勿變更 PostGIS 函數的擁有權。PostGIS 的適當操作和未來升級需要這些函數來保留原始擁有權。如需 PostGIS 許可的詳細資訊，請參閱 [PostgreSQL 安全性](https://postgis.net/workshops/postgis-intro/security.html)。

使用下列函式將 PostGIS 資料表的擁有權移轉至 `gis_admin` 角色。從 psql 提示字元執行下列陳述式來建立函式。

```
CREATE FUNCTION exec(text) returns text language plpgsql volatile AS $f$ BEGIN EXECUTE $1; RETURN $1; END; $f$;
CREATE FUNCTION
```

接下來，執行下列查詢來執行 `exec` 函數，該函數會執行陳述式及變更權限。

```
SELECT exec('ALTER TABLE ' || quote_ident(s.nspname) || '.' || quote_ident(s.relname) || ' OWNER TO gis_admin;')
  FROM (
    SELECT nspname, relname
    FROM pg_class c JOIN pg_namespace n ON (c.relnamespace = n.oid) 
    WHERE nspname in ('tiger','topology') AND
    relkind IN ('r','S','v') ORDER BY relkind = 'S')
s;
```

## 步驟 5：測試擴充功能
<a name="Appendix.PostgreSQL.CommonDBATasks.PostGIS.Test"></a>

為避免需要指定結構描述名稱，請使用下列命令將 `tiger` 結構描述新增至您的搜尋路徑。

```
SET search_path=public,tiger;
SET
```

使用下列 SELECT 陳述式來測試 `tiger` 結構描述。

```
SELECT address, streetname, streettypeabbrev, zip
 FROM normalize_address('1 Devonshire Place, Boston, MA 02109') AS na;
address | streetname | streettypeabbrev |  zip
---------+------------+------------------+-------
       1 | Devonshire | Pl               | 02109
(1 row)
```

要進一步了解此擴充功能，請參閱 PostGIS 文件中的 [Tiger Geocoder](https://postgis.net/docs/Extras.html#Tiger_Geocoder) (Tiger 地理編碼器)。

使用下列 `SELECT` 陳述式來測試存取 `topology` 結構描述。這樣會呼叫 `createtopology` 函數，以使用指定的空間參考識別碼 (26986) 和預設公差 (0.5) 註冊新拓撲物件 (my\$1new\$1topo)。如需進一步了解，請參閱 PostgreGIS 文件中的[建立拓撲](https://postgis.net/docs/CreateTopology.html)。

```
SELECT topology.createtopology('my_new_topo',26986,0.5);
 createtopology
----------------
              1
(1 row)
```

## 步驟 6：升級 PostGIS 擴充功能
<a name="Appendix.PostgreSQL.CommonDBATasks.PostGIS.Update"></a>

每個新版本的 PostgreSQL 都支援一個或多個與該版本相容的 PostGIS 擴充功能版本。將 PostgreSQL 引擎升級到新版本並不會自動升級 PostGIS 擴充功能。升級 PostgreSQL 引擎之前，您通常會將 PostGIS 升級到目前 PostgreSQL 版本的最新可用版本。如需詳細資訊，請參閱[PostGIS 擴充功能版本](#CHAP_PostgreSQL.Extensions.PostGIS)。

PostgreSQL 引擎升級之後，接著再次將 PostGIS 擴充功能升級為支援新升級之 PostgreSQL 引擎版本的版本。如需升級 PostgreSQL 資料庫引擎的詳細資訊，請參閱 [如何執行 RDS for PostgreSQL 的主要版本升級](USER_UpgradeDBInstance.PostgreSQL.MajorVersion.Process.md)。

您可以隨時在 RDS for PostgreSQL 資料庫執行個體上檢查可用的 PostGIS 擴充功能版本更新。若要這麼做，請執行下列命令。PostGIS 2.5.0 和更新版本可使用此功能。

```
SELECT postGIS_extensions_upgrade();
```

如果您的應用程式不支援最新的 PostGIS 版本，您仍然可以安裝主要版本中可用的舊版 PostGIS，如下所示。

```
CREATE EXTENSION postgis VERSION "2.5.5";
```

如果您想要從舊版本升級到特定的 PostGIS 版本，也可以使用以下命令。

```
ALTER EXTENSION postgis UPDATE TO "2.5.5";
```

視您要從哪個版本升級而定，您可能需要再次執行此函數。第一次執行函數的結果會決定是否需要額外的升級函數。例如，這是從 PostGIS 2 升級到 PostGIS 3 的情況。如需詳細資訊，請參閱[將 PostGIS 2 升級到 PostGIS 3](#PostgreSQL.Extensions.PostGIS.versions.upgrading.2-to-3)。

如果您升級此擴充功能以準備 PostgreSQL 引擎的主要版本升級，您可以繼續執行其他初步工作。如需詳細資訊，請參閱 [如何執行 RDS for PostgreSQL 的主要版本升級](USER_UpgradeDBInstance.PostgreSQL.MajorVersion.Process.md)。

## PostGIS 擴充功能版本
<a name="CHAP_PostgreSQL.Extensions.PostGIS"></a>

我們建議您安裝所有擴充功能的版本，例如在《*Amazon RDS for PostgreSQL 版本備註*》中的 [Amazon RDS for PostgreSQL 擴充功能版本](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html)所列出的 PostGIS。若要取得您的發行版本中有哪些可用版本，請使用下列命令。

```
SELECT * FROM pg_available_extension_versions WHERE name='postgis';
```

您也可以在 *Amazon RDS for PostgreSQL 版本備註*的以下各節找到版本資訊：
+ [Amazon RDS 上支援的 PostgreSQL 16 版擴充功能](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html#postgresql-extensions-16x)
+ [Amazon RDS 上支援的 PostgreSQL 15 版擴充功能](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html#postgresql-extensions-15x)
+ [Amazon RDS 上支援的 PostgreSQL 14 版擴充功能](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html#postgresql-extensions-14x)
+ [Amazon RDS 上支援的 PostgreSQL 13 版擴充功能](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html#postgresql-extensions-13x)
+ [Amazon RDS 上支援的 PostgreSQL 12 版擴充功能](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html#postgresql-extensions-12x)
+ [Amazon RDS 上支援的 PostgreSQL 11 版擴充功能](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html#postgresql-extensions-11x)
+ [Amazon RDS 上支援的 PostgreSQL 10 版擴充功能](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html#postgresql-extensions-101x)
+ [Amazon RDS 上支援的 PostgreSQL 9.6.x 版擴充功能](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html#postgresql-extensions-96x)

## 將 PostGIS 2 升級到 PostGIS 3
<a name="PostgreSQL.Extensions.PostGIS.versions.upgrading.2-to-3"></a>

從 3.0 版開始，PostGIS 點陣函數現在是一個單獨的擴充功能，`postgis_raster`。此擴充功能具有自己的安裝和升級路徑。如此一來，可以從核心 `postgis` 擴充功能移除點陣影像處理所需的數十種函數、資料類型和其他成品。這意味著，如果您的使用案例不需要點陣處理，則不需要安裝 `postgis_raster` 擴充功能。

在以下升級範例中，第一個升級命令會將點陣函數擷取至 `postgis_raster` 擴充功能。接著便需要第二個升級命令將 `postgis_raster` 升級到新版本。

**從 PostGIS 2 升級到 PostGIS 3**

1. 識別可用於 PostgreSQL 版本的 PostGIS 預設版本，而其中 PostgreSQL 位於您的 RDS for PostgreSQL 資料庫執行個體。若要這麼做，請執行下列查詢。

   ```
   SELECT * FROM pg_available_extensions
       WHERE default_version > installed_version;
     name   | default_version | installed_version |                          comment
   ---------+-----------------+-------------------+------------------------------------------------------------
    postgis | 3.1.4           | 2.3.7             | PostGIS geometry and geography spatial types and functions
   (1 row)
   ```

1. 識別您的 RDS for PostgreSQL 資料庫執行個體上，每個資料庫中安裝的 PostGIS 版本。換句話說，查詢每個使用者資料庫，如下所示。

   ```
   SELECT
       e.extname AS "Name",
       e.extversion AS "Version",
       n.nspname AS "Schema",
       c.description AS "Description"
   FROM
       pg_catalog.pg_extension e
       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace
       LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid
       AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass
   WHERE
       e.extname LIKE '%postgis%'
   ORDER BY
       1;
     Name   | Version | Schema |                             Description
   ---------+---------+--------+---------------------------------------------------------------------
    postgis | 2.3.7   | public | PostGIS geometry, geography, and raster spatial types and functions
   (1 row)
   ```

   預設版本 (PostGIS 3.1.4) 與安裝的版本 (PostGIS 2.3.7) 之間不符，代表您需要升級 PostGIS 擴充功能。

   ```
   ALTER EXTENSION postgis UPDATE;
   ALTER EXTENSION
   WARNING: unpackaging raster
   WARNING: PostGIS Raster functionality has been unpackaged
   ```

1. 執行下列查詢，以確認點陣函數現在位於其自己的套件中。

   ```
   SELECT
       probin,
       count(*)
   FROM
       pg_proc
   WHERE
       probin LIKE '%postgis%'
   GROUP BY
       probin;
             probin          | count
   --------------------------+-------
    $libdir/rtpostgis-2.3    | 107
    $libdir/postgis-3        | 487
   (2 rows)
   ```

   輸出結果顯示版本之間仍然存在差異。PostGIS 函數是第 3 版 (postgis-3)，而點陣函數 (rtpostgis) 是第 2 版 (rtpostgis-2.3)。若要完成升級，請再次執行升級命令，如下所示。

   ```
   postgres=> SELECT postgis_extensions_upgrade();
   ```

   您可以放心忽略警告訊息。再次執行下列查詢以確認升級是否已完成。當 PostGIS 和所有相關的擴充功能均未標記為需要升級時，則升級完成。

   ```
   SELECT postgis_full_version();
   ```

1. 使用下列查詢來查看已完成的升級程序和個別套裝的擴充功能，並確認其版本是否相符。

   ```
   SELECT
       e.extname AS "Name",
       e.extversion AS "Version",
       n.nspname AS "Schema",
       c.description AS "Description"
   FROM
       pg_catalog.pg_extension e
       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace
       LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid
           AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass
   WHERE
       e.extname LIKE '%postgis%'
   ORDER BY
       1;
         Name      | Version | Schema |                             Description
   ----------------+---------+--------+---------------------------------------------------------------------
    postgis        | 3.1.5   | public | PostGIS geometry, geography, and raster spatial types and functions
    postgis_raster | 3.1.5   | public | PostGIS raster types and functions
   (2 rows)
   ```

   輸出結果顯示 PostGIS 2 擴充功能已升級到 PostGIS 3，並且 `postgis` 和現在的個別 `postgis_raster` 擴充功能則為 3.1.5 版。

升級完成後，如果您不打算使用點陣函數，您可以按以下方式卸除擴充功能。

```
DROP EXTENSION postgis_raster;
```