

# RDS for PostgreSQL での識別可能なバキュームブロック要因の解決
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers"></a>

自動バキュームは積極的なバキュームを実行し、トランザクション ID の経過時間が RDS インスタンスの `autovacuum_freeze_max_age` パラメータで指定されたしきい値に達しないようにします。この経過時間は、Amazon CloudWatch メトリクス `MaximumUsedTransactionIDs` を使用して追跡できます。

Amazon RDS インスタンスの `autovacuum_freeze_max_age` の設定 (デフォルトは 2 億トランザクション ID) を確認するには、次のクエリを使用します。

```
SELECT
    TO_CHAR(setting::bigint, 'FM9,999,999,999') autovacuum_freeze_max_age
FROM
    pg_settings
WHERE
    name = 'autovacuum_freeze_max_age';
```

`postgres_get_av_diag()` では、経過時間が Amazon RDS の[適応型自動バキューム](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AdaptiveAutoVacuuming)のしきい値である 5 億トランザクション ID を超えた場合にのみ、積極的なバキュームのブロック要因をチェックすることに注意してください。`postgres_get_av_diag()` で検出されるブロック要因は、5 億トランザクション以上古いものとなります。

`postgres_get_av_diag()` 関数は、次のタイプのブロック要因を識別します。

**Topics**
+ [アクティブなステートメント](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Active_statement)
+ [トランザクションでのアイドル状態](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Idle_in_transaction)
+ [準備済みトランザクション](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Prepared_transaction)
+ [論理レプリケーションスロット](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Logical_replication_slot)
+ [リードレプリカ](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Read_replicas)
+ [一時テーブル](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Temporary_tables)

## アクティブなステートメント
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Active_statement"></a>

PostgreSQL において、アクティブなステートメントとは、データベースによって現在実行されている SQL ステートメントです。これには、クエリ、トランザクション、または進行中のすべてのオペレーションが含まれます。`pg_stat_activity` を使ってモニタリングする場合、状態列には、対応する PID を持つプロセスがアクティブであることが示されます。

`postgres_get_av_diag()` 関数がアクティブなステートメントであるステートメントを識別すると、次のような出力を表示します。

```
blocker               | Active statement
database              | my_database
blocker_identifier    | SELECT pg_sleep(20000);
wait_event            | Timeout:PgSleep
autovacuum_lagging_by | 568,600,871
suggestion            | Connect to database "my_database", review carefully and you may consider terminating the process using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.
suggested_action      | {"SELECT pg_terminate_backend (29621);"}
```

**推奨されるアクション**

`suggestion` 列のガイダンスに従って、ユーザーはアクティブなステートメントが存在するデータベースに接続できます。`suggested_action` 列で指定されているように、セッションを終了するオプションを慎重に検討することが推奨されます。終了しても安全な場合は、`pg_terminate_backend()` 関数を使用してセッションを終了できます。このアクションは、管理者 (RDS マスターアカウントなど) または必要な `pg_terminate_backend()` 権限を持つユーザーが実行できます。

**警告**  
終了したセッションは、行われた変更を元に戻します (`ROLLBACK`)。要件に応じて、ステートメントを再度実行できます。ただし、自動バキュームプロセスが積極的なバキューム操作を完了した後にのみ実行することをお勧めします。

## トランザクションでのアイドル状態
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Idle_in_transaction"></a>

トランザクションステートメントのアイドル状態とは、明示的なトランザクションを開き (`BEGIN` ステートメントの発行など)、何らかの作業を実行したセッションで、クライアントがさらに作業を渡すか、`COMMIT`、`ROLLBACK`、`END` (暗黙的な `COMMIT` になります) を発行してトランザクションの終了を通知するのを待っているセッションを指します。

`postgres_get_av_diag()` 関数が `idle in transaction` ステートメントをブロック要因として識別すると、次のような出力を表示します。

```
blocker               | idle in transaction
database              | my_database
blocker_identifier    | INSERT INTO tt SELECT * FROM tt;
wait_event            | Client:ClientRead
autovacuum_lagging_by | 1,237,201,759
suggestion            | Connect to database "my_database", review carefully and you may consider terminating the process using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.
suggested_action      | {"SELECT pg_terminate_backend (28438);"}
```

**推奨されるアクション**

`suggestion` 列に示されているように、トランザクションセッションでのアイドル状態が存在するデータベースに接続し、`pg_terminate_backend()` 関数を使用してセッションを終了できます。ユーザーは、管理者 (RDS マスターアカウント) ユーザーでも、 `pg_terminate_backend()` 権限を持つユーザーでもかまいません。

**警告**  
終了したセッションは、行われた変更を元に戻します (`ROLLBACK`)。要件に応じて、ステートメントを再度実行できます。ただし、自動バキュームプロセスが積極的なバキューム操作を完了した後にのみ実行することをお勧めします。

## 準備済みトランザクション
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Prepared_transaction"></a>

PostgreSQL では、[準備済みトランザクション](https://www.postgresql.org/docs/current/sql-prepare-transaction.html)と呼ばれる 2 相コミット戦略の一部であるトランザクションを使用できます。これらは、`max_prepared_transactions` パラメータをゼロ以外の値に設定することで有効になります。準備済みトランザクションは、データベースのクラッシュ、再起動、またはクライアントの切断後も、トランザクションが持続し、引き続き使用できるように設計されています。通常のトランザクションと同様に、トランザクション ID が割り当てられ、自動バキュームに影響を与える場合があります。準備状態のままにすると、自動バキュームはフリーズを実行できず、トランザクション ID の循環につながる可能性があります。

トランザクションマネージャによって解決されることなく無期限に準備状態となったトランザクションは、孤立した準備済みトランザクションになります。これを修正する唯一の方法は、`COMMIT PREPARED` コマンドまたは `ROLLBACK PREPARED` コマンドを使用してトランザクションをコミットするかロールバックすることです。

**注記**  
準備済みトランザクションで作成されたバックアップには、復元後もそのトランザクションが含まれることに注意してください。このようなトランザクションを見つけて閉じる方法については、以下の情報を参照してください。

`postgres_get_av_diag()` 関数が準備済みトランザクションをブロック要因として識別すると、次の出力を表示します。

```
blocker               | Prepared transaction
database              | my_database
blocker_identifier    | myptx
wait_event            | Not applicable
autovacuum_lagging_by | 1,805,802,632
suggestion            | Connect to database "my_database" and consider either COMMIT or ROLLBACK the prepared transaction using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.
suggested_action      | {"COMMIT PREPARED 'myptx';",[OR],"ROLLBACK PREPARED 'myptx';"}
```

**推奨されるアクション**

suggestion 列で説明されているように、準備済みトランザクションがあるデータベースに接続します。`suggested_action` 列に基づいて、`COMMIT` と `ROLLBACK` のどちらを実行するかを慎重に検討し、適切なアクションを選択します。

準備済みトランザクション全般をモニタリングするために、PostgreSQL には `pg_prepared_xacts` というカタログビューが用意されています。次のクエリを使用して、準備済みトランザクションを検索できます。

```
SELECT
    gid,
    prepared,
    owner,
    database,
    transaction AS oldest_xmin
FROM
    pg_prepared_xacts
ORDER BY
    age(transaction) DESC;
```

## 論理レプリケーションスロット
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Logical_replication_slot"></a>

レプリケーションスロットの目的は、ターゲットサーバーにレプリケートされるまで、未使用の変更を保持することです。詳細については、PostgreSQL の「[Logical replication](https://www.postgresql.org/docs/current/logical-replication.html)」を参照してください。

論理レプリケーションスロットには 2 つのタイプがあります。

**非アクティブな論理レプリケーションスロット**

レプリケーションが終了すると、未使用のトランザクションログは削除されず、レプリケーションスロットは非アクティブになります。非アクティブな論理レプリケーションスロットは、現在、サブスクライバーによって使用されていませんが、サーバーには残るため、WAL ファイルが保持され、古いトランザクションログが削除されなくなります。システムは LSN 情報が上書きされないよう保持する必要があるため、ディスク使用量が増加し、具体的には、自動バキュームで内部カタログテーブルをクリーンアップできなくなる可能性があります。放置するとカタログの肥大化とパフォーマンスの低下を招き、循環バキュームのリスクが増大して、トランザクションのダウンタイムが発生する可能性があります。

**アクティブだが遅い論理レプリケーションスロット**

論理レプリケーションのパフォーマンスの低下により、カタログのデッドタプルの削除が遅れることがあります。このレプリケーションの遅延により、`catalog_xmin` の更新が遅れ、カタログの肥大化や循環バキュームが発生する可能性があります。

`postgres_get_av_diag()` 関数が論理レプリケーションスロットをブロック要因として検出すると、次のような出力を表示します。

```
blocker               | Logical replication slot
database              | my_database
blocker_identifier    | slot1
wait_event            | Not applicable
autovacuum_lagging_by | 1,940,103,068
suggestion            | Ensure replication is active and resolve any lag for the slot if active. If inactive, consider dropping it using the command in suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.
suggested_action      | {"SELECT pg_drop_replication_slot('slot1') FROM pg_replication_slots WHERE active = 'f';"}
```

**推奨されるアクション**

この問題を解決するには、レプリケーション設定で、適用プロセスを終了している可能性のあるターゲットスキーマまたはデータの問題を確認します。最も一般的な理由を次に示します。
+ 列の欠落
+ 互換性のないデータ型
+ データの不一致
+ データの欠落

問題がインフラストラクチャの問題に関連している場合
+ ネットワークの問題 - [互換性のないネットワーク状態にある Amazon RDS DB の問題を解決するにはどうすればよいですか?](https://repost.aws/knowledge-center/rds-incompatible-network)
+ データベースまたは DB インスタンスが、次の理由により使用できない
  + レプリカインスタンスのストレージが不足している - 「[Amazon RDS DB インスタンスのストレージが不足したときに発生する問題を解決する方法を教えてください](https://repost.aws/knowledge-center/rds-out-of-storage)」を参照して、ストレージの追加について確認してください。
  + 互換性のないパラメータ - 「[互換性のないパラメータステータスのままになっている Amazon RDS DB インスタンスを修正するにはどうすればよいですか?](https://repost.aws/knowledge-center/rds-incompatible-parameters)」を参照して、問題を解決する方法の詳細を確認してください。

インスタンスが AWS ネットワーク外または AWS EC2 上にある場合は、可用性またはインフラストラクチャ関連の問題の解決方法について管理者に問い合わせてください。

**非アクティブなスロットの削除**

**警告**  
注意: レプリケーションスロットを削除する前に、レプリケーションが進行中ではないこと、レプリケーションスロットが非アクティブで回復不可能な状態であることを慎重に確認してください。スロットを途中で削除すると、レプリケーションが中断されたり、データが失われたりする可能性があります。

レプリケーションスロットが不要になったことを確認したら、削除して自動バキュームを続行できるようにします。条件 `active = 'f'` を指定することで、非アクティブなスロットのみが削除されます。

```
SELECT pg_drop_replication_slot('slot1') WHERE active ='f'
```

## リードレプリカ
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Read_replicas"></a>

[Amazon RDS リードレプリカ](USER_PostgreSQL.Replication.ReadReplicas.md)で `hot_standby_feedback` 設定が有効になっている場合、リードレプリカで実行されているクエリで引き続き必要になる可能性のあるデッド行は、プライマリデータベースの自動バキュームで削除されません。これは、レプリケーションスロットを使用して管理されているかどうかにかかわらず、すべてのタイプの物理リードレプリカに影響します。スタンバイレプリカで実行されているクエリでは、[クエリの競合](https://www.postgresql.org/docs/current/hot-standby.html#HOT-STANDBY-CONFLICT)やキャンセルを防ぐために、これらの行をプライマリで利用できる状態に保つ必要があるため、こうした動作が必要になります。

**物理レプリケーションスロットを使用するリードレプリカ**  
物理レプリケーションスロットを使用するリードレプリカでは、RDS for PostgreSQL でのレプリケーションの信頼性と安定性が大幅に強化されます。これらのスロットにより、プライマリデータベースはレプリカが処理するまで重要なログ先行書き込みファイルを保持し、ネットワークの中断中もデータ整合性を維持できます。

RDS for PostgreSQL バージョン 14 以降、すべてのレプリカでレプリケーションスロットが使用されます。以前のバージョンでは、クロスリージョンレプリカのみでレプリケーションスロットが使用されていました。

`postgres_get_av_diag()` 関数が物理レプリケーションスロットを使用するリードレプリカをブロック要因として検出すると、次のような出力を表示します。

```
blocker               | Read replica with physical replication slot
database              |
blocker_identifier    | rds_us_west_2_db_xxxxxxxxxxxxxxxxxxxxx
wait_event            | Not applicable
autovacuum_lagging_by | 554,080,689
suggestion            | Run the following query on the replica "rds_us_west_2_db_xxxxxxxxxxxxxxxxxxxx" to find the long running query:                           
                      | SELECT * FROM pg_catalog.pg_stat_activity WHERE backend_xmin::text::bigint = 757989377;                                                       
                      | Review carefully and you may consdier terminating the query on read replica using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.                                 +                      |
suggested_action      | {"SELECT pg_terminate_backend(pid) FROM pg_catalog.pg_stat_activity WHERE backend_xmin::text::bigint = 757989377;","                                                                                 +
                      | [OR]                                                                                                                                                                                                 +
                      | ","Disable hot_standby_feedback","                                                                                                                                                                   +
                      | [OR]                                                                                                                                                                                                 +
                      | ","Delete the read replica if not needed"}
```

**ストリーミングレプリケーションを使用するリードレプリカ**  
Amazon RDS では、バージョン 13 までの古いバージョンで、物理レプリケーションスロットを使用せずにリードレプリカを設定できます。このアプローチでは、プライマリが WAL ファイルをより積極的にリサイクルできるようにすることでオーバーヘッドを軽減します。これは、ディスク容量が制限された環境においてメリットがあり、ときどき発生するレプリケーションの遅延も許容できます。ただし、スロットを使用しない場合、WAL ファイルが欠落しないように、スタンバイは同期したままにする必要があります。Amazon RDS は、レプリカが遅れをとった場合にアーカイブされた WAL ファイルを使用して遅れを解消しますが、このプロセスには慎重なモニタリングが必要となり、時間がかかることがあります。

`postgres_get_av_diag()` 関数がストリーミングリードレプリカをブロック要因として検出すると、次のような出力を表示します。

```
blocker               | Read replica with streaming replication slot
database              | Not applicable
blocker_identifier    | xx.x.x.xxx/xx
wait_event            | Not applicable
autovacuum_lagging_by | 610,146,760
suggestion            | Run the following query on the replica "xx.x.x.xxx" to find the long running query:                                                                                                                                                         +
                      | SELECT * FROM pg_catalog.pg_stat_activity WHERE backend_xmin::text::bigint = 348319343;                                                                                                                                                     +
                      | Review carefully and you may consdier terminating the query on read replica using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.                                       +
                      |
suggested_action      | {"SELECT pg_terminate_backend(pid) FROM pg_catalog.pg_stat_activity WHERE backend_xmin::text::bigint = 348319343;","                                                                                                                        +
                      | [OR]                                                                                                                                                                                                                                        +
                      | ","Disable hot_standby_feedback","                                                                                                                                                                                                          +
                      | [OR]                                                                                                                                                                                                                                        +
                      | ","Delete the read replica if not needed"}
```

**推奨されるアクション**

`suggested_action` 列で推奨されているように、以下のオプションを慎重に検討して自動バキュームのブロックを解除します。
+ **クエリを終了する** – suggestion 列のガイダンスに従って、suggested\$1action 列で指定されているようにリードレプリカに接続できます。セッションを終了するオプションは慎重に検討することをお勧めします。終了しても安全であると判断した場合は、`pg_terminate_backend()` 関数を使用してセッションを終了できます。このアクションは、管理者 (RDS マスターアカウントなど) または必要な pg\$1terminate\$1backend() 権限を持つユーザーが実行できます。

  リードレプリカで次の SQL コマンドを実行すると、プライマリのバキュームによる古い行のクリーンアップを妨げているクエリを終了できます。`backend_xmin` の値は、関数の出力で報告されます。

  ```
  SELECT
      pg_terminate_backend(pid)
  FROM
      pg_catalog.pg_stat_activity
  WHERE
      backend_xmin::text::bigint = backend_xmin;
  ```
+ **ホットスタンバイフィードバックを無効にする** – `hot_standby_feedback` パラメータがバキュームの大幅な遅延の原因となっている場合は、これを無効にすることを検討します。

  `hot_standby_feedback` パラメータを使用すると、リードレプリカはクエリアクティビティについてプライマリに通知し、プライマリがスタンバイで使用されているテーブルや行をバキューム処理できないようにします。これによりスタンバイでのクエリの安定性が確保されますが、プライマリでのバキューム処理が大幅に遅延する可能性があります。この機能を無効にすると、プライマリはスタンバイが追いつくのを待たずにバキューム処理を進めることができます。ただし、プライマリによってバキューム処理された行にアクセスしようとすると、スタンバイでクエリのキャンセルや失敗が発生する可能性があります。
+ **不要になったリードレプリカを削除する** – リードレプリカが不要になった場合は、削除できます。これにより、関連するレプリケーションオーバーヘッドが解消され、プライマリがレプリカによって妨げられることなくトランザクションログをリサイクルできるようになります。

## 一時テーブル
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Temporary_tables"></a>

`TEMPORARY` キーワードを使用して作成された[一時テーブル](https://www.postgresql.org/docs/current/sql-createtable.html)は、pg\$1temp\$1xxx などの一時スキーマにあり、それらを作成したセッションのみがアクセスできます。一時テーブルは、セッションが終了すると削除されます。ただし、このようなテーブルは PostgreSQL の自動バキュームプロセスには表示されず、テーブルを作成したセッションによって手動でバキューム処理する必要があります。別のセッションから一時テーブルのバキューム処理を試みても効果はありません。

異常な状況下では、テーブルを所有するアクティブなセッションがない状態で一時テーブルが存在します。致命的なクラッシュ、ネットワークの問題、または同様のイベントが原因でテーブルを所有するセッションが予期せず終了した場合、一時テーブルはクリーンアップされず、「孤立した」テーブルとして残される可能性があります。PostgreSQL 自動バキュームプロセスで孤立した一時テーブルが検出されると、次のメッセージがログに記録されます。

```
LOG: autovacuum: found orphan temp table \"%s\".\"%s\" in database \"%s\"
```

`postgres_get_av_diag()` 関数が一時テーブルをブロック要因として識別すると、次のような出力を表示します。この関数で一時テーブルに関連する出力を正しく表示するには、それらのテーブルが存在するのと同じデータベース内で関数を実行する必要があります。

```
blocker               | Temporary table
database              | my_database
blocker_identifier    | pg_temp_14.ttemp
wait_event            | Not applicable
autovacuum_lagging_by | 1,805,802,632
suggestion            | Connect to database "my_database". Review carefully, you may consider dropping temporary table using command in suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.
suggested_action      | {"DROP TABLE ttemp;"}
```

**推奨されるアクション**

出力の `suggestion` 列に示されている手順に従って、自動バキュームの実行を妨げている一時テーブルを特定して削除します。次のコマンドを使用して、`postgres_get_av_diag()` で報告された一時テーブルを削除します。`postgres_get_av_diag()` 関数で提示された出力に基づいてテーブル名を置き換えます。

```
DROP TABLE my_temp_schema.my_temp_table;
```

次のクエリを使用して、一時テーブルを識別できます。

```
SELECT
    oid,
    relname,
    relnamespace::regnamespace,
    age(relfrozenxid)
FROM
    pg_class
WHERE
relpersistence = 't'
ORDER BY
    age(relfrozenxid) DESC;
```