

# Amazon RDS for PostgreSQL에서 PostgreSQL 자동 정리 사용
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum"></a>

자동 정리 기능을 사용하여 PostgreSQL DB 인스턴스의 상태를 유지 관리하는 것이 좋습니다. Autovacuum은 VACUUM 및 ANALYZE 명령의 시작을 자동화합니다. Autovacuum은 삽입되고 업데이트되거나 삭제된 튜플 수가 많은 테이블이 있는지 확인합니다. 확인이 끝나면 Autovacuum은 PostgreSQL 데이터베이스에서 폐기된 데이터 또는 튜플을 제거하여 스토리지를 회수합니다.

기본적으로 자동 정리는 기본 PostgreSQL DB 파라미터 그룹을 사용하여 만든 RDS for PostgreSQL DB 인스턴스에서 켜져 있습니다. 자동 정리 기능과 관련된 다른 구성 파라미터도 기본적으로 설정됩니다. 이러한 기본값은 다소 일반적이기 때문에 특정 워크로드에 대해 자동 정리 기능과 관련된 일부 파라미터를 조정하면 도움이 될 수 있습니다.

다음에서 자동 정리에 대한 자세한 정보와 RDS for PostgreSQL DB 인스턴스에 대한 파라미터를 조정하는 방법을 확인할 수 있습니다. 더욱 개괄적인 수준의 정보는 [PostgreSQL로 작업하기 위한 모범 사례](CHAP_BestPractices.md#CHAP_BestPractices.PostgreSQL) 섹션을 참조하세요.

**Topics**
+ [Autovacuum에 메모리 할당](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum.WorkMemory)
+ [트랜잭션 ID 랩어라운드의 가능성 감소](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AdaptiveAutoVacuuming)
+ [데이터베이스의 테이블을 vacuum해야 하는지 여부를 결정](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.NeedVacuuming.md)
+ [현재 Autovacuum을 수행할 수 있는 테이블 결정](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.EligibleTables.md)
+ [현재 Autovacuum이 실행 중인지 여부 및 실행 기간 확인](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AutovacuumRunning.md)
+ [수동 vacuum freeze 수행](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.VacuumFreeze.md)
+ [Autovacuum이 실행 중인 경우 테이블 인덱스 다시 지정](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.Reindexing.md)
+ [대용량 인덱스를 사용하여 autovacuum 관리](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.LargeIndexes.md)
+ [Autovacuum에 영향을 주는 기타 파라미터](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.OtherParms.md)
+ [테이블 수준 Autovacuum 파라미터 설정](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.TableParameters.md)
+ [autovacuum 및 vacuum 활동 로그](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.Logging.md)
+ [잘못된 데이터베이스를 사용한 autovacuum 동작 이해](appendix.postgresql.commondbatasks.autovacuumbehavior.md)
+ [RDS for PostgreSQL에서 공격적인 vacuum 블로커 식별 및 해결](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.md)

## Autovacuum에 메모리 할당
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.WorkMemory"></a>

autovacuum 성능에 영향을 미치는 가장 중요한 파라미터 중 하나는 [https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-AUTOVACUUM-WORK-MEM](https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-AUTOVACUUM-WORK-MEM) 파라미터입니다. RDS for PostgreSQL 버전 14 이하에서는 `autovacuum_work_mem` 파라미터가 -1로 설정되어 `maintenance_work_mem`의 설정이 대신 사용됨을 나타냅니다. 다른 모든 버전의 경우 `autovacuum_work_mem`는 GREATEST(\$1DBInstanceClassMemory/32768\$1, 65536)에 의해 결정됩니다.

수동 vacuum 작업은 항상 기본 `maintenance_work_mem` 설정인 GREATEST(\$1DBInstanceClassMemory/63963136\$11024\$1, 65536)을 사용하며, 보다 대상화된 수동 `VACUUM` 작업을 위해 `SET` 명령을 사용하여 세션 수준에서 조정할 수도 있습니다.

`autovacuum_work_mem`는 인덱스 vacuum용 데드 튜플(`pg_stat_all_tables.n_dead_tup`)의 ID를 저장하기 위한 autovacuum 메모리를 결정합니다.

`autovacuum_work_mem` 파라미터 값을 결정하기 위해 계산할 때는 다음 사항에 유의하세요.
+ 파라미터를 너무 낮게 설정하면 vacuum 프로세스가 테이블을 여러 번 스캔해야 작업이 완료될 수 있습니다. 이러한 다중 스캔은 성능에 부정적인 영향을 줄 수 있습니다. 더 큰 인스턴스의 경우 `maintenance_work_mem` 또는 `autovacuum_work_mem`을 최소 1GB로 설정하면 데드 튜플 수가 많은 테이블을 vacuum하는 성능이 향상될 수 있습니다. 그러나 PostgreSQL 버전 16 이하에서는 vacuum 메모리 사용량이 1GB로 제한되므로 한 번의 전달로 약 1억 7,900만 개의 데드 튜플을 처리하기에 충분합니다. 테이블에 이보다 더 많은 데드 튜플이 있는 경우 vacuum은 테이블의 인덱스를 여러 번 전달해야 하므로 필요한 시간이 크게 늘어납니다. PostgreSQL 버전 17부터는 1GB의 제한이 없으며, autovacuum은 radix 트리를 사용하여 1억 7,900만 개 이상의 튜플을 처리할 수 있습니다.

  튜플 식별자의 크기는 6바이트입니다. 테이블의 인덱스를 vacuum하는 데 필요한 메모리를 추정하려면 `pg_stat_all_tables.n_dead_tup`를 쿼리하여 데드 튜플 수를 찾은 다음 이 수에 6을 곱하여 인덱스를 단일 전달로 vacuum하는 데 필요한 메모리를 결정합니다. 다음 쿼리를 사용할 수 있습니다.

  ```
  SELECT
      relname AS table_name,
      n_dead_tup,
      pg_size_pretty(n_dead_tup * 6) AS estimated_memory
  FROM
      pg_stat_all_tables
  WHERE
      relname = 'name_of_the_table';
  ```
+ `autovacuum_work_mem` 파라미터는 `autovacuum_max_workers` 파라미터와 함께 작동합니다. `autovacuum_max_workers` 중 각각의 작업자는 할당된 메모리를 사용할 수 있습니다. 작은 테이블이 많이 있는 경우에는 `autovacuum_max_workers`를 더 많이 할당하고 `autovacuum_work_mem`을 더 적게 할당합니다. 큰 테이블이 많이 있는 경우(100GB 이상)에는 메모리를 더 많이 할당하고 작업자 프로세스를 더 적게 할당합니다. 가장 큰 테이블에서 성공적으로 작업을 수행하려면 충분한 메모리를 할당해 두어야 합니다. 따라서 작업자 프로세스와 메모리를 합한 양이 할당하려는 전체 메모리 양과 같아야 합니다.

## 트랜잭션 ID 랩어라운드의 가능성 감소
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AdaptiveAutoVacuuming"></a>

경우에 따라 Autovacuum과 관련된 파라미터 그룹 설정이 트랜잭션 ID 랩어라운드를 방지하기에 충분히 공격적이지 않을 수 있습니다. 이를 해결하기 위해 RDS for PostgreSQL은 자동 정리 파라미터 값을 자동으로 조정하는 메커니즘을 제공합니다. *적응형 자동 정리*는 RDS for PostgreSQL의 기능입니다. [TransactionID wraparound](https://www.postgresql.org/docs/current/static/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND)에 대한 자세한 설명은 PostgreSQL 설명서에 나와 있습니다.

동적 파라미터 `rds.adaptive_autovacuum`이 켜짐으로 설정된 RDS for PostgreSQL 인스턴스의 경우 적응형 자동 정리가 기본적으로 켜져 있습니다. 이 설정을 항상 활성화해 놓는 것이 좋습니다. 그러나 적응형 Autovacuum 파라미터 튜닝을 끄려면 `rds.adaptive_autovacuum` 파라미터를 0 또는 OFF로 설정합니다.

Amazon RDS Amazon RDS가 자동 정리 파라미터를 조정하더라도 트랜잭션 ID 랩어라운드는 계속 가능합니다. 트랜잭션 ID 랩어라운드에 대한 Amazon CloudWatch 경보를 구현하는 것이 좋습니다. 자세한 내용은 AWS 데이터베이스 블로그의 [RDS for PostgreSQL에서 트랜잭션 ID 랩어라운드에 대한 조기 경고 시스템 구축](https://aws.amazon.com/blogs/database/implement-an-early-warning-system-for-transaction-id-wraparound-in-amazon-rds-for-postgresql/) 게시물을 참조하세요.

적응형 자동 정리 파라미터 튜닝을 사용 설정한 경우 Amazon RDS는 CloudWatch 지표 `MaximumUsedTransactionIDs`가 `autovacuum_freeze_max_age` 파라미터 값 또는 500,000,000 중 큰 값에 도달하면 자동 정리 파라미터를 조정하기 시작합니다.

테이블이 계속 트랜잭션 ID 랩어라운드 방향으로 향하면 Amazon RDS는 Autovacuum의 파라미터를 계속 조정합니다. 이러한 각각의 조정은 랩어라운드를 피하기 위해 Autovacuum에 더 많은 리소스를 할애합니다. Amazon RDS는 다음 자동 정리 관련 파라미터를 업데이트합니다.
+ [autovacuum\$1vacuum\$1cost\$1delay](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-VACUUM-COST-DELAY)
+ [ autovacuum\$1vacuum\$1cost\$1limit](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-VACUUM-COST-LIMIT)
+  [https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-AUTOVACUUM-WORK-MEM](https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-AUTOVACUUM-WORK-MEM) 
+  [autovacuum\$1naptime](https://www.postgresql.org/docs/current/runtime-config-autovacuum.html#GUC-AUTOVACUUM-NAPTIME) 

RDS는 새 값이 Autovacuum을 보다 공격적으로 만드는 경우에만 이러한 파라미터를 수정합니다. 파라미터는 DB 인스턴스의 메모리에서 수정됩니다. 파라미터 그룹의 값은 변경되지 않습니다. 현재 인 메모리 설정을 보려면 PostgreSQL [SHOW](https://www.postgresql.org/docs/current/sql-show.html) SQL 명령을 사용하십시오.

Amazon RDS가 이러한 Autovacuum 파라미터를 수정하면 영향받은 DB 인스턴스에 대한 이벤트를 생성합니다. 이 이벤트는 AWS Management Console 및 Amazon RDS API에서 볼 수 있습니다. `MaximumUsedTransactionIDs` CloudWatch 지표가 임계값 미만의 값을 반환하면 Amazon RDS는 메모리의 자동 정리 관련 파라미터를 파라미터 그룹에 지정된 값으로 다시 설정합니다. 그런 다음 이 변경에 해당하는 다른 이벤트를 생성합니다.

# 데이터베이스의 테이블을 vacuum해야 하는지 여부를 결정
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.NeedVacuuming"></a>

다음 쿼리를 사용하여 데이터베이스의 고정되지 않은 트랜잭션 수를 표시할 수 있습니다. 데이터베이스 `datfrozenxid` 행의 `pg_database` 열은 해당 데이터베이스에 나타나는 정상 트랜잭션 ID의 하한값입니다. 이 열은 데이터베이스 내 테이블 단위 `relfrozenxid` 값 중 최소값입니다.

```
SELECT datname, age(datfrozenxid) FROM pg_database ORDER BY age(datfrozenxid) desc limit 20;
```

예를 들어 앞의 쿼리를 실행하면 다음과 같은 결과가 나올 수 있습니다.

```
datname    | age
mydb       | 1771757888
template0  | 1721757888
template1  | 1721757888
rdsadmin   | 1694008527
postgres   | 1693881061
(5 rows)
```

데이터베이스의 수명이 20억 트랜잭션 ID에 도달하면 트랜잭션 ID(XID) 랩어라운드가 발생하고 데이터베이스는 읽기 전용이 됩니다. 이 쿼리를 사용하면 지표를 생성하여 하루에 몇 번 실행되도록 할 수 있습니다. 기본적으로 autovacuum은 트랜잭션 수명을 200,000,000([https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-FREEZE-MAX-AGE](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-FREEZE-MAX-AGE)) 미만으로 유지하도록 설정됩니다.

샘플 모니터링 전략은 다음과 같습니다.
+ `autovacuum_freeze_max_age` 값을 2억 개 트랜잭션으로 설정하십시오.
+ 테이블이 5억 개의 고정되지 않은 트랜잭션에 도달하면 낮은 심각도 경보가 트리거됩니다. 이 값은 타당한 값이지만 autovacuum이 계속 수행되고 있지 않음을 나타낼 수 있습니다.
+ 테이블 수명이 10억이 되면 조치를 취해야 할 경보로 처리되어야 합니다. 성능상의 이유로 수명을 `autovacuum_freeze_max_age`에 더 가깝게 유지하려는 경우가 대부분입니다. 다음 권장 사항을 사용하여 조사하는 것이 좋습니다.
+ 테이블이 15억 개의 vacuum되지 않은 트랜잭션에 도달하면 높은 심각도 경보가 트리거됩니다. 데이터베이스가 트랜잭션 ID를 사용하는 속도에 따라 이 경보는 시스템에서 autovacuum을 실행할 시간이 부족함을 나타낼 수 있습니다. 이 경우 즉시 이를 해결하는 것이 좋습니다.

테이블이 지속적으로 이 임계값을 위반하면 autovacuum 파라미터를 추가로 수정합니다. 기본적으로 수동 VACUUM을 사용하면(비용에 따른 지연이 비활성화됨)은 기본 autovacuum을 사용할 때보다 더 적극적이지만 시스템 전체에 더 많이 침입할 수 있는 상태이기도 합니다.

다음과 같이 하는 것이 좋습니다.
+ 모니터링 메커니즘을 숙지하고 활성화하여 가장 오래된 트랜잭션의 수명을 확인합니다.

  트랜잭션 ID 랩어라운드에 대해 경고하는 프로세스 생성에 대한 자세한 내용은 AWS 데이터베이스 블로그 게시물 [Amazon RDS for PostgreSQL의 트랜잭션 ID 랩어라운드용 조기 경고 시스템 구현](https://aws.amazon.com/blogs/database/implement-an-early-warning-system-for-transaction-id-wraparound-in-amazon-rds-for-postgresql/)을 참조하세요.
+ 더 많이 사용되는 테이블의 경우 autovacuum을 사용하는 것 이외에 유지 관리 기간 동안 수동 vacuum freeze를 정기적으로 수행합니다. 수동 vacuum freeze 수행에 대한 자세한 내용은 [수동 vacuum freeze 수행](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.VacuumFreeze.md) 단원을 참조하십시오.

# 현재 Autovacuum을 수행할 수 있는 테이블 결정
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.EligibleTables"></a>

vacuum을 수행해야 하는 테이블이 하나이거나 두 개인 경우가 많습니다. `relfrozenxid` 값이 `autovacuum_freeze_max_age`의 트랜잭션 수보다 큰 테이블은 항상 Autovacuum의 대상이 됩니다. 그렇지 않은 경우 VACUUM이 "vacuum 임계값"을 초과하여 튜플 수가 더 이상 사용되지 않는 경우 테이블이 vacuum됩니다.

[autovacuum 임계값](https://www.postgresql.org/docs/current/static/routine-vacuuming.html#AUTOVACUUM)은 다음과 같이 정의되어 있습니다.

```
Vacuum-threshold = vacuum-base-threshold + vacuum-scale-factor * number-of-tuples
```

여기서 `vacuum base threshold`는 `autovacuum_vacuum_threshold`이고, `vacuum scale factor`는 `autovacuum_vacuum_scale_factor`이며, `number of tuples`는 `pg_class.reltuples`입니다.

데이터베이스에 연결되어 있는 상태에서 다음 쿼리를 실행하여 autovacuum이 vacuum 가능한 대상으로 분류하는 테이블 목록을 확인합니다.

```
WITH vbt AS (SELECT setting AS autovacuum_vacuum_threshold FROM 
pg_settings WHERE name = 'autovacuum_vacuum_threshold'),
vsf AS (SELECT setting AS autovacuum_vacuum_scale_factor FROM 
pg_settings WHERE name = 'autovacuum_vacuum_scale_factor'), 
fma AS (SELECT setting AS autovacuum_freeze_max_age FROM pg_settings WHERE name = 'autovacuum_freeze_max_age'),
sto AS (select opt_oid, split_part(setting, '=', 1) as param,
split_part(setting, '=', 2) as value from (select oid opt_oid, unnest(reloptions) setting from pg_class) opt)
SELECT '"'||ns.nspname||'"."'||c.relname||'"' as relation,
pg_size_pretty(pg_table_size(c.oid)) as table_size,
age(relfrozenxid) as xid_age,
coalesce(cfma.value::float, autovacuum_freeze_max_age::float) autovacuum_freeze_max_age,
(coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) +
coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * c.reltuples)
AS autovacuum_vacuum_tuples, n_dead_tup as dead_tuples FROM
pg_class c join pg_namespace ns on ns.oid = c.relnamespace 
join pg_stat_all_tables stat on stat.relid = c.oid join vbt on (1=1) join vsf on (1=1) join fma on (1=1)
left join sto cvbt on cvbt.param = 'autovacuum_vacuum_threshold' and c.oid = cvbt.opt_oid 
left join sto cvsf on cvsf.param = 'autovacuum_vacuum_scale_factor' and c.oid = cvsf.opt_oid
left join sto cfma on cfma.param = 'autovacuum_freeze_max_age' and c.oid = cfma.opt_oid
WHERE c.relkind = 'r' and nspname <> 'pg_catalog'
AND (age(relfrozenxid) >= coalesce(cfma.value::float, autovacuum_freeze_max_age::float)
OR coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) + 
coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * 
c.reltuples <= n_dead_tup)
ORDER BY age(relfrozenxid) DESC LIMIT 50;
```

# 현재 Autovacuum이 실행 중인지 여부 및 실행 기간 확인
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AutovacuumRunning"></a>

테이블을 수동으로 vacuum해야 하는 경우 autovacuum이 현재 실행 중인지 확인합니다. 실행 중이면 더 효율적으로 실행되도록 파라미터를 수정하거나 VACUUM을 수동으로 실행할 수 있도록 일시적으로 autovacuum을 종료해야 합니다.

다음 쿼리를 사용하여 autovacuum이 실행 중인지 여부와 얼마 동안 실행되고 있는지, 다른 세션에 대해 대기하고 있는지 확인합니다.

```
SELECT datname, usename, pid, state, wait_event, current_timestamp - xact_start AS xact_runtime, query
FROM pg_stat_activity 
WHERE upper(query) LIKE '%VACUUM%' 
ORDER BY xact_start;
```

쿼리를 실행하면 다음과 유사한 출력이 표시됩니다.

```
 datname | usename  |  pid  | state  | wait_event |      xact_runtime       | query  
 --------+----------+-------+--------+------------+-------------------------+--------------------------------------------------------------------------------------------------------
 mydb    | rdsadmin | 16473 | active |            | 33 days 16:32:11.600656 | autovacuum: VACUUM ANALYZE public.mytable1 (to prevent wraparound)
 mydb    | rdsadmin | 22553 | active |            | 14 days 09:15:34.073141 | autovacuum: VACUUM ANALYZE public.mytable2 (to prevent wraparound)
 mydb    | rdsadmin | 41909 | active |            | 3 days 02:43:54.203349  | autovacuum: VACUUM ANALYZE public.mytable3
 mydb    | rdsadmin |   618 | active |            | 00:00:00                | SELECT datname, usename, pid, state, wait_event, current_timestamp - xact_start AS xact_runtime, query+
         |          |       |        |            |                         | FROM pg_stat_activity                                                                                 +
         |          |       |        |            |                         | WHERE query like '%VACUUM%'                                                                           +
         |          |       |        |            |                         | ORDER BY xact_start;                                                                                  +
```

몇 가지 문제로 인해 autovacuum 세션이 오래(며칠간) 실행될 수 있습니다. 이 문제는 대부분 [https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM](https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM) 파라미터 값이 테이블 크기 또는 업데이트 속도에 대해 너무 낮게 설정된 경우입니다.

다음 공식을 사용하여 `maintenance_work_mem` 파라미터 값을 설정하는 것이 좋습니다.

```
GREATEST({DBInstanceClassMemory/63963136*1024},65536)
```

짧은 기간 동안 실행되는 autovacuum 세션에서도 문제를 표시할 수 있습니다.
+ 워크로드에 `autovacuum_max_workers`가 충분하지 않다고 표시될 수 있습니다. 이 경우 작업자 수를 명시해야 합니다.
+ 인덱스 손상(autovacuum에 충돌이 발생하여 동일한 관계에서 다시 시작되지만 진행되지 않음)이 있다고 표시될 수 있습니다. 이 경우에는 `vacuum freeze verbose table` 매뉴얼을 실행하여 정확한 원인을 확인합니다.

# 수동 vacuum freeze 수행
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.VacuumFreeze"></a>

vacuum 프로세스가 실행되고 있는 테이블에서 수동 vacuum을 수행하려는 경우가 있습니다. 이 작업은 수명이 20억 개 트랜잭션에 도달하거나 모니터링 중인 임계값을 초과한 테이블을 파악해 둔 경우 유용합니다.

다음 단계는 지침으로 이 프로세스를 여러 가지로 변형할 수 있습니다. 예를 들어 테스트 중에 [https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM](https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM) 파라미터 값이 너무 작게 설정되었고 테이블에 작업을 즉시 수행해야 한다고 가정해보겠습니다. 그러나 지금은 인스턴스를 반송하고 싶지 않을 수도 있습니다. 이전 세션의 쿼리를 사용하여 어떤 테이블이 문제이고 오랜 기간 동안 실행 중인 autovacuum 세션이 있는지 확인합니다. `maintenance_work_mem` 파라미터 설정도 변경해야 하지만 즉시 조치를 취해 문제가 되는 테이블을 vacuum해야 하기도 합니다. 이 경우 어떤 작업을 수행해야 하는지가 다음 절차에 나와 있습니다.

**vacuum freeze를 수동으로 수행하려면**

1. vacuum할 테이블이 포함되어 있는 데이터베이스에 세션 두 개를 엽니다. 두 번째 세션의 경우 "screen"을 사용하거나 연결이 끊긴 경우 세션을 유지하는 다른 유틸리티를 사용합니다.

1. 첫 번째 세션에서는 테이블에서 실행 중인 autovacuum 세션의 프로세스 ID(PID)를 가져옵니다.

   다음 쿼리를 실행하여 autovacuum 세션의 PID를 가져옵니다.

   ```
   SELECT datname, usename, pid, current_timestamp - xact_start 
   AS xact_runtime, query
   FROM pg_stat_activity WHERE upper(query) LIKE '%VACUUM%' ORDER BY 
   xact_start;
   ```

1. 세션 2에서 이 작업에 필요한 메모리 양을 계산합니다. 이 예제에서는 이 작업에 메모리를 최대 2GB까지 사용할 수 있는 것으로 보고 현재 세션의 [https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM](https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM)을 2GB로 설정합니다.

   ```
   SET maintenance_work_mem='2 GB';
   SET
   ```

1. 세션 2에서 테이블에 대한 `vacuum freeze verbose` 명령을 실행하십시오. 현재 PostgreSQL에서 이 작업에 대한 진행률 보고가 없음에도 작업을 확인할 수 있기 때문에 상세 정보 표시 설정이 유용하게 사용됩니다.

   ```
   \timing on
   Timing is on.
   vacuum freeze verbose pgbench_branches;
   ```

   ```
   INFO:  vacuuming "public.pgbench_branches"
   INFO:  index "pgbench_branches_pkey" now contains 50 row versions in 2 pages
   DETAIL:  0 index row versions were removed.
   0 index pages have been deleted, 0 are currently reusable.
   CPU 0.00s/0.00u sec elapsed 0.00 sec.
   INFO:  index "pgbench_branches_test_index" now contains 50 row versions in 2 pages
   DETAIL:  0 index row versions were removed.
   0 index pages have been deleted, 0 are currently reusable.
   CPU 0.00s/0.00u sec elapsed 0.00 sec.
   INFO:  "pgbench_branches": found 0 removable, 50 nonremovable row versions 
        in 43 out of 43 pages
   DETAIL:  0 dead row versions cannot be removed yet.
   There were 9347 unused item pointers.
   0 pages are entirely empty.
   CPU 0.00s/0.00u sec elapsed 0.00 sec.
   VACUUM
   Time: 2.765 ms
   ```

1. 세션 1에서 autovacuum이 vacuum 세션을 차단한 경우 `pg_stat_activity`에서 vacuum 세션에 대한 대기를 나타내는 `T`를 확인할 수 있습니다. 이 경우 다음과 같이 autovacuum 프로세스를 종료합니다.

   ```
   SELECT pg_terminate_backend('the_pid'); 
   ```
**참고**  
Amazon RDS의 일부 하위 버전은 위의 명령을 사용하여 autovacuum 프로세스를 종료할 수 없으며 `ERROR: 42501: must be a superuser to terminate superuser process LOCATION: pg_terminate_backend, signalfuncs.c:227` 오류와 함께 작업이 실패합니다. 

   이때 세션이 시작됩니다. 이 테이블이 작업 목록에서 가장 상위에 있을 것이므로 autovacuum이 즉시 재시작됩니다.

1. 세션 2에서 `vacuum freeze verbose` 명령을 시작한 다음 세션 1에서 autovacuum 프로세스를 종료합니다.

# Autovacuum이 실행 중인 경우 테이블 인덱스 다시 지정
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.Reindexing"></a>

인덱스가 손상되면 autovacuum은 계속해서 테이블을 처리하려 하고 실패합니다. 이 경우 수동 vacuum을 시도하면 다음과 비슷한 오류 메시지가 표시됩니다.

```
postgres=>  vacuum freeze pgbench_branches;
ERROR: index "pgbench_branches_test_index" contains unexpected 
   zero page at block 30521
HINT: Please REINDEX it.
```

인덱스가 손상된 상태에서 테이블에 대해 autovacuum을 실행하려고 하면 이미 실행 중인 autovacuum 세션이 있음을 확인하게 됩니다. [REINDEX](https://www.postgresql.org/docs/current/static/sql-reindex.html) 명령을 실행하면 테이블에 대한 단독 잠금을 해제합니다. 쓰기 작업과 해당 특정 인덱스를 사용하는 읽기 작업도 차단됩니다.

**테이블에서 autovacuum을 실행할 때 테이블 인덱스를 다시 지정하려면**

1. vacuum할 테이블이 포함되어 있는 데이터베이스에 세션 두 개를 엽니다. 두 번째 세션의 경우 "screen"을 사용하거나 연결이 끊긴 경우 세션을 유지하는 다른 유틸리티를 사용합니다.

1. 첫 번째 세션에서는 테이블에서 실행 중인 autovacuum 세션의 PID를 가져옵니다.

   다음 쿼리를 실행하여 autovacuum 세션의 PID를 가져옵니다.

   ```
   SELECT datname, usename, pid, current_timestamp - xact_start 
   AS xact_runtime, query
   FROM pg_stat_activity WHERE upper(query) like '%VACUUM%' ORDER BY 
   xact_start;
   ```

1. 세션 2에서 reindex 명령을 실행합니다.

   ```
   \timing on
   Timing is on.
   reindex index pgbench_branches_test_index;
   REINDEX
     Time: 9.966 ms
   ```

1. 세션 1에서 autovacuum이 프로세스를 차단한 경우 `pg_stat_activity`에서 vacuum 세션에 대한 대기를 나타내는 "T"를 확인할 수 있습니다. 이 경우에는 autovacuum 프로세스를 종료합니다.

   ```
   SELECT pg_terminate_backend('the_pid');
   ```

   이때 세션이 시작됩니다. 이 테이블이 작업 목록에서 가장 상위에 있을 것이므로 autovacuum이 즉시 다시 시작된다는 점을 알아 두어야 합니다.

1. 세션 2에서 명령을 시작한 다음 세션 1에서 autovacuum 프로세스를 종료합니다.

# 대용량 인덱스를 사용하여 autovacuum 관리
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.LargeIndexes"></a>

작업 중에 *autovacuum*은 테이블에서 실행되는 동안 여러 [ vacuum 단계를](https://www.postgresql.org/docs/current/progress-reporting.html#VACUUM-PHASES) 수행합니다. 테이블을 정리하기 전에 먼저 모든 인덱스에 vacuum을 실행합니다. 여러 개의 대용량 인덱스를 제거할 경우, 이 단계는 상당한 시간과 리소스를 사용합니다. 따라서 테이블의 인덱스 수를 제어하고 사용하지 않는 인덱스를 제거하는 것이 가장 좋습니다.

이 프로세스에서는 먼저 전체 인덱스 크기를 확인합니다. 그런 다음, 다음 예제에 나온 것처럼 제거할 수 있는 사용하지 않는 인덱스가 있는지 확인합니다.

**테이블 및 해당 인덱스의 크기를 확인하려면**

```
postgres=> select pg_size_pretty(pg_relation_size('pgbench_accounts'));
pg_size_pretty
6404 MB
(1 row)
```

```
postgres=> select pg_size_pretty(pg_indexes_size('pgbench_accounts'));
pg_size_pretty
11 GB
(1 row)
```

이 예제에서는 인덱스 크기가 테이블보다 큽니다. 이러한 차이로 인해 인덱스가 팽창하거나 사용되지 않아 성능 문제가 발생하여 autovacuum 및 삽입 작업에 영향을 미칠 수 있습니다.

**사용하지 않는 인덱스를 확인하려면**

[https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-ALL-INDEXES-VIEW](https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-ALL-INDEXES-VIEW) 보기를 사용하면 인덱스가 `idx_scan` 열에 사용되는 빈도를 확인할 수 있습니다. 다음 예제를 보면 사용하지 않은 인덱스는 `idx_scan` 값이 `0`입니다.

```
postgres=> select * from pg_stat_user_indexes where relname = 'pgbench_accounts' order by idx_scan desc;
    
relid  | indexrelid | schemaname | relname          | indexrelname          | idx_scan | idx_tup_read | idx_tup_fetch
-------+------------+------------+------------------+-----------------------+----------+--------------+---------------
16433  | 16454      | public     | pgbench_accounts | index_f               | 6        | 6            | 0
16433  | 16450      | public     | pgbench_accounts | index_b               | 3        | 199999       | 0
16433  | 16447      | public     | pgbench_accounts | pgbench_accounts_pkey | 0        | 0            | 0
16433  | 16452      | public     | pgbench_accounts | index_d               | 0        | 0            | 0
16433  | 16453      | public     | pgbench_accounts | index_e               | 0        | 0            | 0
16433  | 16451      | public     | pgbench_accounts | index_c               | 0        | 0            | 0
16433  | 16449      | public     | pgbench_accounts | index_a               | 0        | 0            | 0
(7 rows)
```

```
postgres=> select schemaname, relname, indexrelname, idx_scan from pg_stat_user_indexes where relname = 'pgbench_accounts' order by idx_scan desc;
    
schemaname  | relname          | indexrelname          | idx_scan
------------+------------------+-----------------------+----------
public      | pgbench_accounts | index_f               | 6
public      | pgbench_accounts | index_b               | 3
public      | pgbench_accounts | pgbench_accounts_pkey | 0
public      | pgbench_accounts | index_d               | 0
public      | pgbench_accounts | index_e               | 0
public      | pgbench_accounts | index_c               | 0
public      | pgbench_accounts | index_a               | 0
(7 rows)
```

**참고**  
이러한 통계는 통계가 재설정된 시점부터 증분됩니다. 사업 분기 말에만 사용되거나 특정 보고서에만 사용되는 인덱스가 있는 경우를 가정해 보겠습니다. 통계가 재설정된 이후로 이 인덱스가 사용되지 않았을 수 있습니다. 자세한 내용은 [Statistics Functions](https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-STATS-FUNCTIONS)(통계 함수)를 참조하세요. 고유성을 적용하는 데 사용되는 인덱스는 스캔이 실행되지 않으므로 사용하지 않는 인덱스로 식별해선 안 됩니다. 사용하지 않는 인덱스를 식별하려면 애플리케이션 및 해당 쿼리에 대한 심층적인 지식이 있어야 합니다.

데이터베이스의 통계가 마지막으로 재설정된 시간을 확인하려면 [ https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-DATABASE-VIEW]( https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-DATABASE-VIEW)를 사용하세요.

```
postgres=> select datname, stats_reset from pg_stat_database where datname = 'postgres';
    
datname   | stats_reset
----------+-------------------------------
postgres  | 2022-11-17 08:58:11.427224+00
(1 row)
```

## 테이블에 최대한 신속하게 Vacuum을 실행하는 방법
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.LargeIndexes.Executing"></a>

**RDS for PostgreSQL 12 이상**

대형 테이블에 인덱스가 너무 많으면 DB 인스턴스가 트랜잭션 ID 랩어라운드(XID)에 가까워질 수 있는데, 이때 XID 카운터가 0으로 래핑됩니다. 이 옵션을 선택하지 않으면 데이터가 손실될 수 있습니다. 그러나 인덱스를 정리하지 않고도 테이블에 신속하게 vacuum을 실행할 수 있습니다. RDS for PostgreSQL 12에서는 [https://www.postgresql.org/docs/current/sql-vacuum.html](https://www.postgresql.org/docs/current/sql-vacuum.html) 절과 함께 VACUUM을 사용할 수 있습니다.

```
postgres=> VACUUM (INDEX_CLEANUP FALSE, VERBOSE TRUE) pgbench_accounts;
        
INFO: vacuuming "public.pgbench_accounts"
INFO: table "pgbench_accounts": found 0 removable, 8 nonremovable row versions in 1 out of 819673 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 7517
Skipped 0 pages due to buffer pins, 0 frozen pages.
CPU: user: 0.01 s, system: 0.00 s, elapsed: 0.01 s.
```

autovacuum 세션이 이미 실행 중인 경우, 해당 세션을 종료하여 수동 VACUUM을 시작해야 합니다. 수동 vacuum freeze 수행에 대한 자세한 내용은 [수동 vacuum freeze 수행](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.VacuumFreeze.md) 섹션을 참조하세요.

**참고**  
주기적인 인덱스 정리를 건너뛰면 인덱스 팽창이 발생하여 스캔 성능이 다운그레이드될 수 있습니다. 인덱스는 데드 행을 유지하고 테이블은 데드 라인 포인터를 유지합니다. 따라서 `pg_stat_all_tables.n_dead_tup`는 인덱스 정리가 포함된 수동 VACUUM 또는 autovacuum이 실행될 때까지 증가합니다. 가장 좋은 방법은 이 프로시저만 사용하여 트랜잭션 ID 랩어라운드를 방지하는 것입니다.

**RDS for PostgreSQL 11 이상**

그러나 RDS for PostgreSQL 11 이하 버전에서 vacuum을 더 신속하게 완료할 수 있는 유일한 방법은 테이블의 인덱스 수를 줄이는 것입니다. 인덱스를 삭제하면 쿼리 계획에 영향을 미칠 수 있습니다. 사용하지 않는 인덱스를 먼저 삭제한 다음, XID 랩어라운드가 매우 가까워졌을 때 인덱스를 삭제하는 것이 좋습니다. vacuum 프로세스가 완료되면 이러한 인덱스를 다시 생성할 수 있습니다.

# Autovacuum에 영향을 주는 기타 파라미터
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.OtherParms"></a>

이 쿼리를 사용하면 autovacuum 및 해당 동작에 직접 영향을 주는 일부 파라미터 값이 표시됩니다. [autovacuum 파라미터](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html)는 PostgreSQL 설명서에 자세히 설명되어 있습니다.

```
SELECT name, setting, unit, short_desc
FROM pg_settings
WHERE name IN (
'autovacuum_max_workers',
'autovacuum_analyze_scale_factor',
'autovacuum_naptime',
'autovacuum_analyze_threshold',
'autovacuum_analyze_scale_factor',
'autovacuum_vacuum_threshold',
'autovacuum_vacuum_scale_factor',
'autovacuum_vacuum_threshold',
'autovacuum_vacuum_cost_delay',
'autovacuum_vacuum_cost_limit',
'vacuum_cost_limit',
'autovacuum_freeze_max_age',
'maintenance_work_mem',
'vacuum_freeze_min_age');
```

모두 autovacuum에 영향을 주지만 가장 중요한 사항 몇 가지는 다음과 같습니다.
+ [maintenance\$1work\$1mem](https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE_WORK_MEM)
+ [autovacuum\$1freeze\$1max\$1age](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-FREEZE-MAX-AGE)
+ [autovacuum\$1max\$1workers](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-MAX-WORKERS)
+ [autovacuum\$1vacuum\$1cost\$1delay](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-VACUUM-COST-DELAY)
+ [ autovacuum\$1vacuum\$1cost\$1limit](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-VACUUM-COST-LIMIT)

# 테이블 수준 Autovacuum 파라미터 설정
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.TableParameters"></a>

Autovacuum이 관련된 [스토리지 파라미터](https://www.postgresql.org/docs/current/static/sql-createtable.html#SQL-CREATETABLE-STORAGE-PARAMETERS)를 테이블 수준에서 설정할 수 있습니다. 이 방법은 전체 데이터베이스의 동작을 변경하는 방법보다 더 나을 수 있습니다. 큰 테이블에 적극적인 설정을 지정해야 하지만 autovacuum이 모든 테이블에서 이와 같은 방식으로 작동하지 않도록 하려는 경우가 있을 수 있습니다.

이 쿼리를 사용하면 현재 어떤 테이블에 테이블 수준 옵션을 사용 중인지가 표시됩니다.

```
SELECT relname, reloptions
FROM pg_class
WHERE reloptions IS NOT null;
```

이 쿼리가 유용한 경우는 테이블 하나가 나머지 테이블보다 훨씬 더 큰 경우입니다. 300GB 테이블 하나와 1GB 미만의 테이블 30개가 있다고 가정하십시오. 이 경우 더 큰 테이블에 특정 파라미터를 설정하여 전체 시스템의 동작이 변경되지 않도록 할 수 있습니다.

```
ALTER TABLE mytable set (autovacuum_vacuum_cost_delay=0);
```

이렇게 하면 시스템의 리소스를 더 많이 사용하는 대신 이 테이블의 비용에 따른 autovacuum 지연이 비활성화됩니다. 일반적으로 매시간 `autovacuum_cost_limit`에 도달한 `autovacuum_vacuum_cost_delay`의 autovacuum이 일시 중지됩니다. 자세한 내용은 [비용에 따른 vacuum 수행](https://www.postgresql.org/docs/current/static/runtime-config-resource.html#RUNTIME-CONFIG-RESOURCE-VACUUM-COST)에 대한 PostgreSQL 설명서에서 확인할 수 있습니다.

# autovacuum 및 vacuum 활동 로그
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.Logging"></a>

autovacuum 활동에 대한 정보는 `rds.force_autovacuum_logging_level` 파라미터에 지정된 레벨을 기반으로 `postgresql.log`에 전송됩니다. 다음은 이 파라미터와 PostgreSQL 버전에 허용되는 해당 값이 기본 설정인 값입니다.
+ `disabled`(PostgreSQL 10, PostgreSQL 9.6)
+ `debug5`, `debug4`, `debug3`, `debug2`, `debug1`
+ `info`(PostgreSQL 12, PostgreSQL 11)
+ `notice`
+ `warning`(PostgreSQL 13 이상)
+ `error`, 로그, `fatal`, `panic` 

`rds.force_autovacuum_logging_level`은 `log_autovacuum_min_duration` 파라미터와 함께 작동합니다. `log_autovacuum_min_duration` 파라미터 값은 autovacuum 작업이 기록되는 임계값(밀리초) 이상입니다. `-1`로 설정하면 아무것도 기록하지 않지만 0으로 설정하면 모든 작업이 기록됩니다. `rds.force_autovacuum_logging_level`과 마찬가지로 `log_autovacuum_min_duration`의 기본값은 다음과 같이 버전에 따라 다릅니다.
+ `10000 ms` - PostgreSQL 14, PostgreSQL 13, PostgreSQL 12, PostgreSQL 11 
+ `(empty)` - PostgreSQL 10 및 PostgreSQL 9.6 기본값 없음

`rds.force_autovacuum_logging_level`을 `WARNING`로 설정하는 것이 좋습니다. 또한 `log_autovacuum_min_duration`을 1000에서 5000까지의 값으로 설정하는 것이 좋습니다. 5,000밀리초 이상 걸리는 5000개의 기록 활동 설정. -1을 제외한 모든 설정은 충돌하는 잠금 또는 동시에 삭제된 관계로 인해 autovacuum 작업을 건너뛴 경우에도 메시지를 기록합니다. 자세한 내용은 PostgreSQL 설명서의 [자동 Vacuuming](https://www.postgresql.org/docs/current/runtime-config-autovacuum.html)을 참조하세요.

문제를 해결하려면 `rds.force_autovacuum_logging_level` 매개 변수를 상세 표시 정보에 대해 `debug1`부터 `debug5`까지의 디버그 레벨 중 하나로 변경할 수 있습니다. 디버그 설정은 단기 문제 해결 목적으로만 사용하는 것이 좋습니다. 자세한 내용은 PostgreSQL의 [로그 시기](https://www.postgresql.org/docs/current/static/runtime-config-logging.html#RUNTIME-CONFIG-LOGGING-WHEN) 문서를 참조하세요.

**참고**  
PostgreSQL을 사용하면 `rds_superuser` 계정에서 `pg_stat_activity`의 autovacuum 세션을 볼 수 있습니다. 예: 명령의 실행을 차단하거나, 수동으로 실행한 vacuum 명령보다 느리게 실행되는 autovacuum 세션을 식별 및 종료 가능

# 잘못된 데이터베이스를 사용한 autovacuum 동작 이해
<a name="appendix.postgresql.commondbatasks.autovacuumbehavior"></a>

 DROP DATABASE 작업 도중에 중단된 데이터베이스를 유효하지 않은 것으로 나타내는 새 `-2` 값이 `pg_database` 카탈로그의 `datconnlimit` 열에 도입되었습니다.

 이 새 값은 다음과 같은 RDS for PostgreSQL 버전에서 사용할 수 있습니다.
+ 15.4 이상의 모든 버전
+ 14.9 이상 버전
+ 13.12 이상 버전
+ 12.16 이상 버전
+ 11.21 이상 버전

잘못된 데이터베이스는 유효한 데이터베이스의 기능을 중지하는 autovacuum 기능에 영향을 주지 않습니다. autovacuum은 잘못된 데이터베이스를 무시합니다. 따라서 PostgreSQL 환경의 모든 유효한 데이터베이스에 대해 정기적인 vacuum 작업이 계속해서 적절하고 효율적으로 작동합니다.

**Topics**
+ [트랜잭션 ID 모니터링](#appendix.postgresql.commondbatasks.autovacuum.monitorxid)
+ [모니터링 쿼리 조정](#appendix.postgresql.commondbatasks.autovacuum.monitoradjust)
+ [잘못된 데이터베이스 문제 해결](#appendix.postgresql.commondbatasks.autovacuum.connissue)

## 트랜잭션 ID 모니터링
<a name="appendix.postgresql.commondbatasks.autovacuum.monitorxid"></a>

 `age(datfrozenxid)` 함수는 일반적으로 데이터베이스의 트랜잭션 ID(XID) 수명을 모니터링하여 트랜잭션 ID 랩어라운드를 방지하는 데 사용됩니다.

 유효하지 않은 데이터베이스는 autovacuum에서 제외되므로, 트랜잭션 ID(XID) 횟수가 최대값인 `2 billion`에 도달하여 `- 2 billion`로 순환하며 이 주기를 무한정 계속할 수 있습니다. 트랜잭션 ID 랩어라운드를 모니터링하는 일반적인 쿼리는 다음과 같습니다.

```
SELECT max(age(datfrozenxid)) FROM pg_database;
```

그러나 `datconnlimit`에 대한 -2 값이 도입되면 잘못된 데이터베이스가 이 쿼리의 결과를 왜곡할 수 있습니다. 이러한 데이터베이스는 유효하지 않으며 정기적인 유지 관리 검사에 포함되어서는 안 되므로, 오탐을 유발할 수 있어 실제보다 `age(datfrozenxid)`가 높다고 믿게 됩니다.

## 모니터링 쿼리 조정
<a name="appendix.postgresql.commondbatasks.autovacuum.monitoradjust"></a>

 정확한 모니터링을 위해서는 잘못된 데이터베이스를 제외하도록 모니터링 쿼리를 조정해야 합니다. 다음 권장 쿼리를 따르세요.

```
SELECT
    max(age(datfrozenxid))
FROM
    pg_database
WHERE
    datconnlimit <> -2;
```

이 쿼리를 사용하면 PostgreSQL 환경 전체의 트랜잭션 ID 사용 기간을 정확하게 반영하여 유효한 데이터베이스만 `age(datfrozenxid)` 계산에 고려합니다.

## 잘못된 데이터베이스 문제 해결
<a name="appendix.postgresql.commondbatasks.autovacuum.connissue"></a>

 잘못된 데이터베이스에 연결하려고 하면 다음과 같은 오류 메시지가 표시될 수 있습니다.

```
postgres=> \c db1
connection to server at "mydb.xxxxxxxxxx.us-west-2.rds.amazonaws.com" (xx.xx.xx.xxx), port xxxx failed: FATAL:  cannot connect to invalid database "db1"
HINT:  Use DROP DATABASE to drop invalid databases.
Previous connection kept
```

 또한, `log_min_messages` 파라미터가 `DEBUG2` 이상으로 설정된 경우 autovacuum 프로세스가 잘못된 데이터베이스를 건너뛰고 있음을 나타내는 다음과 같은 로그 항목을 확인할 수 있습니다.

```
       
2024-07-30 05:59:00 UTC::@:[32000]:DEBUG:  autovacuum: skipping invalid database "db6"
2024-07-30 05:59:00 UTC::@:[32000]:DEBUG:  autovacuum: skipping invalid database "db1"
```

이 문제를 해결하려면 연결 시도 중에 제공된 `HINT`를 따르세요. RDS 마스터 계정 또는 `rds_superuser` 역할이 있는 데이터베이스 계정을 사용하여 유효한 데이터베이스에 연결하고 잘못된 데이터베이스를 삭제합니다.

```
SELECT
    'DROP DATABASE ' || quote_ident(datname) || ';'
FROM
    pg_database
WHERE
    datconnlimit = -2 \gexec
```

# RDS for PostgreSQL에서 공격적인 vacuum 블로커 식별 및 해결
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring"></a>

PostgreSQL에서는 vacuum 작업이 스토리지를 회수하고 [트랜잭션 ID 랩어라운드](https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND) 문제를 방지하기 때문에 데이터베이스의 좋은 상태를 위해 vacuum 작업이 중요합니다. 그러나 vacuum 작업이 원하는 대로 작동하지 않게 되는 경우가 있어 성능이 저하되고, 스토리지가 팽창하고, 트랜잭션 ID 랩어라운드로 인해 DB 인스턴스의 가용성이 영향을 받을 수 있습니다. 따라서 최적의 데이터베이스 성능과 가용성을 위해서는 이러한 문제를 식별하고 해결하는 것이 필수적입니다. Autovacuum에 대해 자세히 알아보려면 [Understanding autovacuum in Amazon RDS for PostgreSQL environments](https://aws.amazon.com/blogs/database/understanding-autovacuum-in-amazon-rds-for-postgresql-environments/)를 읽어보세요.

`postgres_get_av_diag()` 함수는 공격적 vacuum 진행 상황을 방지하거나 지연시키는 문제를 식별하는 데 도움이 됩니다. 제안이 제공되며, 여기에는 문제를 식별할 수 있는 경우 문제 해결을 위한 명령이, 문제를 식별할 수 없는 경우 추가 진단을 위한 지침이 포함될 수 있습니다. 공격적 vacuum 블로커는 연령이 RDS의 [적응형 autovacuum](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AdaptiveAutoVacuuming) 임곗값인 트랜잭션 ID 5억 개를 초과할 때 보고됩니다.

**트랜잭션 ID의 연령이란 무엇인가요?**

트랜잭션 ID에 대한 `age()` 함수는 데이터베이스(`pg_database.datfrozenxid`) 또는 테이블(`pg_class.relfrozenxid`)에 대해 가장 오래된 고정되지 않은 트랜잭션 ID 이후 발생한 트랜잭션 수를 계산합니다. 이 값은 마지막 공격적 vacuum 작업 이후의 데이터베이스 활동을 나타내며 향후 VACUUM 프로세스에 대해 가능한 워크로드를 강조합니다.

**공격적 vacuum이란 무엇인가요?**

공격적인 VACUUM 작업은 일반적인 VACUUM에서는 대개 건너 뛰는 페이지를 포함하여 테이블 내에 있는 모든 페이지에 대한 종합적인 스캔을 수행합니다. 이 철저한 스캔의 목표는 최대 연령에 근접한 트랜잭션 ID를 '고정'하여 [트랜잭션 ID 랩어라운드](https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND)라고 하는 상황을 효과적으로 방지하는 것을 목표로 합니다.

`postgres_get_av_diag()`가 블로커를 보고하려면 블로커의 연령이 최소 5억 개의 트랜잭션이어야 합니다.

**Topics**
+ [RDS for PostgreSQL에 자동 정리 모니터링 및 진단 도구 설치](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Installation.md)
+ [RDS for PostgreSQL의 postgres\$1get\$1av\$1diag() 기능](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Functions.md)
+ [RDS for PostgreSQL에서 식별 가능한 vacuum 블로커 해결](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md)
+ [RDS for PostgreSQL에서 식별 불가능한 vacuum 블로커 해결](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Unidentifiable_blockers.md)
+ [RDS for PostgreSQL의 vacuum 성능 문제 해결](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Performance.md)
+ [RDS for PostgreSQL의 NOTICE 메시지 설명](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.NOTICE.md)

# RDS for PostgreSQL에 자동 정리 모니터링 및 진단 도구 설치
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Installation"></a>

`postgres_get_av_diag()` 함수는 현재 다음 RDS for PostgreSQL 버전에서 사용할 수 있습니다.
+ 17.2 이상의 17 버전
+ 16.7 이상의 16 버전
+ 15.11 이상의 15 버전
+ 14.16 이상의 14 버전
+ 13.19 이상의 13 버전

 `postgres_get_av_diag()`를 사용하려면 `rds_tools` 확장을 만듭니다.

```
postgres=> CREATE EXTENSION rds_tools ;
CREATE EXTENSION
```

확장이 설치되어 있는지 확인합니다.

```
postgres=> \dx rds_tools
             List of installed extensions
   Name    | Version |  Schema   |                    Description
 ----------+---------+-----------+----------------------------------------------------------
 rds_tools |   1.8   | rds_tools | miscellaneous administrative functions for RDS PostgreSQL
 1 row
```

함수가 만들어졌는지 확인합니다.

```
postgres=> SELECT
    proname function_name,
    pronamespace::regnamespace function_schema,
    proowner::regrole function_owner
FROM
    pg_proc
WHERE
    proname = 'postgres_get_av_diag';
    function_name     | function_schema | function_owner
----------------------+-----------------+----------------
 postgres_get_av_diag | rds_tools       | rds_superuser
(1 row)
```

# RDS for PostgreSQL의 postgres\$1get\$1av\$1diag() 기능
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Functions"></a>

`postgres_get_av_diag()` 함수는 RDS for PostgreSQL 데이터베이스에서 차단하거나 지연되는 자동 정리 프로세스에 대한 진단 정보를 검색합니다. 정확한 결과를 얻으려면 가장 오래된 트랜잭션 ID로 데이터베이스에서 쿼리를 실행해야 합니다. 가장 오래된 트랜잭션 ID로 데이터베이스를 사용하는 방법에 대한 자세한 내용은 [Not connected to the database with the age of oldest transaction ID](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.NOTICE.md)를 참조하세요.

```
SELECT
    blocker,
    DATABASE,
    blocker_identifier,
    wait_event,
    TO_CHAR(autovacuum_lagging_by, 'FM9,999,999,999') AS autovacuum_lagging_by,
    suggestion,
    suggested_action
FROM (
    SELECT
        *
    FROM
        rds_tools.postgres_get_av_diag ()
    ORDER BY
        autovacuum_lagging_by DESC) q;
```

`postgres_get_av_diag()` 함수는 다음 정보를 반환합니다.

**blocker**  
Vacuum을 차단하는 데이터베이스 활동의 범주를 보여줍니다.  
+ [활성 문](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Active_statement)
+ [트랜잭션의 유휴 상태](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Idle_in_transaction)
+ [준비된 트랜잭션](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Prepared_transaction)
+ [논리적 복제 슬롯](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Logical_replication_slot)
+ [물리적 복제 슬롯을 사용하는 읽기 전용 복제본](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Read_replicas)
+ [스트리밍 복제를 사용하는 읽기 전용 복제본](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Read_replicas)
+ [임시 테이블](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Temporary_tables)

**데이터베이스**  
적용 가능하고 지원되는 경우 데이터베이스의 이름을 보여줍니다. 활동이 진행 중이고 autovacuum을 차단 중이거나 차단할 데이터베이스입니다. 연결하고 조치를 취해야 하는 데이터베이스입니다.

**blocker\$1identifier**  
Autovacuum을 차단 중이거나 차단할 활동의 식별자를 보여줍니다. 식별자는 SQL 문, 준비된 트랜잭션, 읽기 전용 복제본의 IP 주소, 논리적 또는 물리적 복제 슬롯의 이름과 함께 프로세스 ID일 수 있습니다.

**wait\$1event**  
차단 세션의 [대기 이벤트](PostgreSQL.Tuning.md) 를 지정하고 다음 블로커에 적용할 수 있습니다.  
+ 활성 문
+ 트랜잭션의 유휴 상태

**autovacum\$1lagging\$1by**  
범주당 백로그 작업에서 autovacuum이 지연되는 트랜잭션 수를 보여줍니다.

**suggestion**  
블로커를 해결하기 위한 제안을 보여줍니다. 이러한 지침에는 해당하는 경우 활동이 존재하는 데이터베이스의 이름, 해당하는 경우 세션의 프로세스 ID(PID) 및 수행할 작업이 포함됩니다.

**suggested\$1action**  
블로커를 해결하기 위해 수행해야 하는 작업을 제안합니다.

# RDS for PostgreSQL에서 식별 가능한 vacuum 블로커 해결
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers"></a>

Autovacuum은 공격적인 vacuum을 수행하고 트랜잭션 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의 [적응형 autovacuum](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AdaptiveAutoVacuuming) 임곗값인 트랜잭션 ID 5억 개를 초과할 때만 공격적 vacuum 블로커를 확인합니다. `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`) 변경 사항을 취소합니다. 요구 사항에 따라 문을 다시 실행할 수 있습니다. 그러나 autovacuum 프로세스가 공격적인 vacuum 작업을 완료한 후에만 다시 실행하는 것이 좋습니다.

## 트랜잭션의 유휴 상태
<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`) 변경 사항을 취소합니다. 요구 사항에 따라 문을 다시 실행할 수 있습니다. 그러나 autovacuum 프로세스가 공격적인 vacuum 작업을 완료한 후에만 다시 실행하는 것이 좋습니다.

## 준비된 트랜잭션
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Prepared_transaction"></a>

PostgreSQL은 [준비된 트랜잭션](https://www.postgresql.org/docs/current/sql-prepare-transaction.html)이라고 하는 두 단계 커밋 전략의 일부인 트랜잭션을 허용합니다. `max_prepared_transactions` 파라미터를 0이 아닌 값으로 설정하면 활성화됩니다. 준비된 트랜잭션은 데이터베이스 충돌, 재시작 또는 클라이언트 연결 해제 후에도 트랜잭션이 내구성을 유지하고 계속 가능하도록 하기 위해 설계되었습니다. 일반 트랜잭션과 마찬가지로 트랜잭션 ID가 할당되며 autovacuum에 영향을 미칠 수 있습니다. 준비된 상태로 두면 autovacuum이 고정을 수행할 수 없으며 트랜잭션 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';"}
```

**권장 조치**

제안 열에 언급된 대로 준비된 트랜잭션이 있는 데이터베이스에 연결합니다. `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)을 참조하세요.

논리적 복제 슬롯에는 두 가지 유형이 있습니다.

**비활성 논리적 복제 슬롯**

복제가 종료되면 소비되지 않은 트랜잭션 로그를 제거할 수 없으며 복제 슬롯이 비활성화됩니다. 비활성 논리적 복제 슬롯은 현재 구독자가 사용하지 않지만 서버에 남아 있어 WAL 파일이 보존되고 이전 트랜잭션 로그를 제거할 수 없습니다. 이렇게 되면 LSN 정보를 덮어쓰지 않도록 시스템이 보존해야 하므로 디스크 사용량이 증가하고 특히 autovacuum이 내부 카탈로그 테이블을 정리하지 못하게 됩니다. 해결하지 않으면 카탈로그 팽창, 성능 저하 및 랩어라운드 vacuum 위험 증가로 이어질 수 있으며 이로 인해 트랜잭션 가동 중지 시간이 발생할 수도 있습니다.

**활성이지만 느린 논리적 복제 슬롯**

논리적 복제의 성능 저하로 인해 카탈로그의 데드 튜플 제거가 지연되는 경우가 있습니다. 이러한 복제 지연으로 인해 `catalog_xmin`의 업데이트 속도가 느려지고 카탈로그 팽창 및 랩어라운드 vacuum이 발생할 수 있습니다.

`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 instances run out of storage](https://repost.aws/knowledge-center/rds-out-of-storage)를 검토하세요.
  + 호환되지 않는 파라미터 - 문제를 해결하는 방법에 대한 자세한 내용은 [호환되지 않는 파라미터 상태에서 멈춘 Amazon RDS DB 인스턴스를 해결하려면 어떻게 해야 하나요?](https://repost.aws/knowledge-center/rds-incompatible-parameters)를 검토하세요.

인스턴스가 AWS 네트워크 외부 또는 AWS EC2에 있는 경우 관리자에게 가용성 또는 인프라 관련 문제를 해결하는 방법을 문의하세요.

**비활성 슬롯 삭제**

**주의**  
주의: 복제 슬롯을 삭제하기 전에 복제가 진행 중이지 않고 비활성 상태이며 복구할 수 없는 상태인지 주의 깊게 확인합니다. 슬롯을 성급히 삭제하면 복제가 중단되거나 데이터가 손실될 수 있습니다.

복제 슬롯이 더 이상 필요하지 않음을 확인한 후 autovacuum이 계속되도록 슬롯을 삭제합니다. `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` 설정이 활성화된 경우 기본 데이터베이스의 autovacuum이 읽기 전용 복제본에서 실행되는 쿼리에 여전히 필요할 수 있는 데드 행을 제거하는 것을 방지합니다. 이는 복제 슬롯을 사용하거나 사용하지 않고 관리되는 복제본을 포함하여 모든 유형의 물리적 읽기 전용 복제본에 영향을 미칩니다. 대기 복제본에서 실행되는 쿼리가 [쿼리 충돌](https://www.postgresql.org/docs/current/hot-standby.html#HOT-STANDBY-CONFLICT) 및 취소를 방지하면서 기본에서 해당 행을 계속 사용 가능하도록 요구하기 때문에 이 동작이 필요합니다.

**물리적 복제 슬롯을 사용하는 읽기 전용 복제본**  
물리적 복제 슬롯을 사용하는 읽기 전용 복제본은 RDS for PostgreSQL에서 복제의 신뢰성과 안정성을 크게 향상시킵니다. 이러한 슬롯은 복제본이 처리할 때까지 기본 데이터베이스가 필수 Write-Ahead Log 파일을 유지하여 네트워크 중단 중에도 데이터 일관성을 유지하도록 합니다.

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 파일을 더 공격적으로 재활용할 수 있도록 하여 오버헤드를 줄입니다. 이는 디스크 공간이 제한되고 가끔 ReplicaLag를 허용할 수 있는 환경에서 유용합니다. 그러나 슬롯이 없으면 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` 열에서 권장하는 대로 이러한 옵션을 주의 깊게 검토하여 autovacuum 차단을 해제합니다.
+ **쿼리 종료** - 제안 열의 지침에 따라 suggested\$1action 열에 지정된 대로 읽기 전용 복제본에 연결할 수 있습니다. 세션을 종료하는 옵션을 주의 깊게 검토하는 것이 좋습니다. 종료가 안전한 것으로 간주되는 경우 `pg_terminate_backend()` 함수를 사용하여 세션을 종료할 수 있습니다. 이 작업은 관리자(예: RDS 마스터 계정) 또는 필요한 pg\$1terminate\$1backend() 권한이 있는 사용자가 수행할 수 있습니다.

  읽기 전용 복제본에서 다음 SQL 명령을 실행하여 기본의 vacuum이 오래된 행을 정리하지 못하게 하는 쿼리를 종료할 수 있습니다. `backend_xmin`의 값은 함수의 출력에 보고됩니다.

  ```
  SELECT
      pg_terminate_backend(pid)
  FROM
      pg_catalog.pg_stat_activity
  WHERE
      backend_xmin::text::bigint = backend_xmin;
  ```
+ **상시 대기 피드백 비활성화** - `hot_standby_feedback` 파라미터가 심각한 vacuum 지연을 일으키는 경우 해당 파라미터를 비활성화하는 것을 고려합니다.

  `hot_standby_feedback` 파라미터를 사용하면 읽기 전용 복제본이 기본에 쿼리 활동을 알려 기본이 대기에서 사용 중인 테이블이나 행을 정리하지 못하도록 할 수 있습니다. 이렇게 하면 대기의 쿼리 안정성이 보장되지만 기본의 vacuum이 크게 지연될 수 있습니다. 이 기능을 비활성화하면 대기가 따라잡기를 기다리지 않고 기본이 vacuum 작업을 진행할 수 있습니다. 그러나 기본이 정리한 행에 대기가 액세스하려고 하면 대기에서 쿼리 취소 또는 실패가 발생할 수 있습니다.
+ **필요하지 않은 경우 읽기 전용 복제본 삭제** - 읽기 전용 복제본이 더 이상 필요하지 않은 경우 삭제할 수 있습니다. 이렇게 하면 연결된 복제 오버헤드가 제거되고 기본이 복제본에 의해 지연되지 않고 트랜잭션 로그를 재활용할 수 있습니다.

## 임시 테이블
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Temporary_tables"></a>

`TEMPORARY` 키워드를 사용하여 만든 [임시 테이블](https://www.postgresql.org/docs/current/sql-createtable.html)은 pg\$1temp\$1xxx와 같은 임시 스키마에 상주하며 해당 테이블을 만든 세션에서만 액세스할 수 있습니다. 세션이 종료되면 임시 테이블이 삭제됩니다. 그러나 이러한 테이블은 PostgreSQL의 autovacuum 프로세스에는 보이지 않으며 테이블을 만든 세션에서 수동으로 vacuum 처리해야 합니다. 다른 세션에서 임시 테이블을 정리하려고 해도 아무런 효과가 없습니다.

비정상적인 상황에서는 임시 테이블이 활성 세션 없이 존재합니다. 치명적인 충돌, 네트워크 문제 또는 유사한 이벤트로 인해 소유 세션이 예기치 않게 종료되는 경우 임시 테이블이 정리되지 않아 '고립된' 테이블로 남겨질 수 있습니다. PostgreSQL autovacuum 프로세스가 고립된 임시 테이블을 감지하면 다음 메시지를 로깅합니다.

```
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` 열에 제공된 지침에 따라 autovacuum 실행을 막는 임시 테이블을 식별하고 제거합니다. 다음 명령을 사용하여 `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;
```

# RDS for PostgreSQL에서 식별 불가능한 vacuum 블로커 해결
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Unidentifiable_blockers"></a>

이 섹션에서는 vacuum 작업이 진행되지 않는 다른 이유를 살펴봅니다. 이러한 문제는 현재 `postgres_get_av_diag()` 함수를 사용하여 직접 식별할 수 없습니다.

**Topics**
+ [유효하지 않은 페이지](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Invalid_pages)
+ [인덱스 불일치](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Index_inconsistency)
+ [매우 높은 트랜잭션 속도](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.High_transaction_rate)

## 유효하지 않은 페이지
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Invalid_pages"></a>

유효하지 않은 페이지 오류는 PostgreSQL이 해당 페이지에 액세스하는 동안 페이지의 체크섬에서 불일치를 감지할 때 발생합니다. 내용을 읽을 수 없어 autovacuum이 튜플을 고정시킬 수 없습니다. 이로 인해 정리 프로세스가 중지됩니다. 다음 오류가 PostgreSQL의 로그에 기록됩니다.

```
WARNING:  page verification failed, calculated checksum YYYYY but expected XXXX
ERROR:  invalid page in block ZZZZZ of relation base/XXXXX/XXXXX
CONTEXT:  automatic vacuum of table myschema.mytable
```

**객체 유형 확인**

```
ERROR: invalid page in block 4305910 of relation base/16403/186752608 
WARNING: page verification failed, calculated checksum 50065 but expected 60033
```

오류 메시지에서 `base/16403/186752608` 경로는 다음 정보를 제공합니다.
+ 'base'는 PostgreSQL 데이터 디렉터리 아래의 디렉터리 이름입니다.
+ '16403'은 `pg_database` 시스템 카탈로그에서 조회할 수 있는 데이터베이스 OID입니다.
+ '186752608'은 `pg_class` 시스템 카탈로그에서 스키마 및 객체 이름을 조회하는 데 사용할 수 있는 `relfilenode`입니다.

영향을 받는 데이터베이스에서 다음 쿼리의 출력을 확인하여 객체 유형을 확인할 수 있습니다. 다음 쿼리는 oid가 186752608인 객체 정보를 검색합니다. OID를 발생한 오류와 관련된 OID로 바꿉니다.

```
SELECT
    relname AS object_name,
    relkind AS object_type,
    nspname AS schema_name
FROM
    pg_class c
    JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE
    c.oid = 186752608;
```

자세한 내용은 PostgreSQL 설명서의 [https://www.postgresql.org/docs/current/catalog-pg-class.html](https://www.postgresql.org/docs/current/catalog-pg-class.html)에서 `pg_class`의 `relkind` 열에 표시된 지원되는 모든 객체 유형을 참조하세요.

**지침**

이 문제에 대한 가장 효과적인 솔루션은 특정 Amazon RDS 인스턴스의 구성과 불일치 페이지의 영향을 받는 데이터 유형에 따라 달라집니다.

**객체 유형이 인덱스인 경우:**

인덱스를 다시 구축하는 것이 좋습니다.
+ **`CONCURRENTLY` 옵션 사용** - PostgreSQL 버전 12 전에는 인덱스를 다시 구축하려면 테이블에 대한 액세스를 제한하는 배타적인 테이블 잠금이 필요했습니다. PostgreSQL 버전 12 이상에서는 `CONCURRENTLY` 옵션을 사용하여 행 수준 잠금을 허용하므로 테이블의 가용성이 크게 향상됩니다. 다음은 명령입니다.

  ```
  REINDEX INDEX ix_name CONCURRENTLY;
  ```

  `CONCURRENTLY`는 중단이 덜 시키지만 사용량이 많은 테이블에서는 속도가 느릴 수 있습니다. 가능하면 트래픽이 적은 기간에 인덱스를 구축하는 것이 좋습니다.

  자세한 내용은 PostgreSQL [REINDEX](https://www.postgresql.org/docs/current/sql-reindex.html) 설명서를 참조하세요.
+ **`INDEX_CLEANUP FALSE` 옵션 사용** - 인덱스가 크고 완료하는 데 상당한 시간이 필요할 것으로 예상되는 경우 인덱스를 제외하면서 수동 `VACUUM FREEZE`를 실행하여 autovacuum 차단을 해제할 수 있습니다. 이 기능은 PostgreSQL 버전 12 이상에서 사용할 수 있습니다.

  인덱스를 우회하면 일관되지 않은 인덱스의 vacuum 프로세스를 건너뛰고 랩어라운드 문제를 완화할 수 있습니다. 그러나 이렇게 해도 기본 유효하지 않은 페이지 문제는 해결되지 않습니다. 유효하지 않은 페이지 문제를 완전히 해결하려면 인덱스를 다시 구축해야 합니다.

**객체 유형이 구체화된 뷰인 경우:**

구체화된 뷰에서 유효하지 않은 페이지 오류가 발생하면 영향을 받는 데이터베이스에 로그인하고 새로 고쳐 유효하지 않은 페이지를 해결합니다.

구체화된 뷰를 새로 고침:

```
REFRESH MATERIALIZED VIEW schema_name.materialized_view_name;
```

새로 고침이 실패하면 다시 만들기 시도:

```
DROP MATERIALIZED VIEW schema_name.materialized_view_name;
CREATE MATERIALIZED VIEW schema_name.materialized_view_name AS query;
```

구체화된 뷰를 새로 고치거나 다시 만들면 기본 테이블 데이터에 영향을 주지 않고 복원됩니다.

**다른 모든 객체 유형의 경우:**

다른 모든 객체 유형의 경우 AWS Support에 문의하세요.

## 인덱스 불일치
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Index_inconsistency"></a>

논리적으로 일치하지 않는 인덱스는 autovacuum이 진행되는 것을 방지할 수 있습니다. 다음 오류 또는 유사한 오류는 인덱스의 vacuum 단계 동안 또는 SQL 문에서 인덱스에 액세스할 때 로깅됩니다.

```
ERROR: right sibling's left-link doesn't match:block 5 links to 10 instead of expected 2 in index ix_name
```

```
ERROR: failed to re-find parent key in index "XXXXXXXXXX" for deletion target page XXX
CONTEXT:  while vacuuming index index_name of relation schema.table
```

**지침**

인덱스를 다시 구축하거나 수동 `VACUUM FREEZE`에서 `INDEX_CLEANUP`을 사용하여 인덱스를 건너뜁니다. 인덱스를 다시 구축하는 방법에 대한 자세한 내용은 [객체 유형이 인덱스인 경우](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Invalid_pages)를 참조하세요.
+ **CONCURRENTLY 옵션 사용** – PostgreSQL 버전 12 전에는 인덱스를 다시 구축하려면 테이블에 대한 액세스를 제한하는 배타적인 테이블 잠금이 필요했습니다. PostgreSQL 버전 12 이상에서는 CONCURRENTLY 옵션을 사용하여 행 수준 잠금을 허용하므로 테이블의 가용성이 크게 향상됩니다. 다음은 명령입니다.

  ```
  REINDEX INDEX ix_name CONCURRENTLY;
  ```

  CONCURRENTLY는 중단이 적지만 사용량이 많은 테이블에서는 속도가 느릴 수 있습니다. 가능하면 트래픽이 적은 기간에 인덱스를 구축하는 것이 좋습니다. 자세한 내용은 *PostgreSQL* 설명서의 [REINDEX](https://www.postgresql.org/docs/current/sql-reindex.html)를 참조하세요.
+ **INDEX\$1CLEANUP FALSE 옵션 사용** - 인덱스가 크고 완료하는 데 상당한 시간이 필요할 것으로 예상되는 경우 인덱스를 제외하면서 수동 VACUUM FREEZE를 실행하여 autovacuum 차단을 해제할 수 있습니다. 이 기능은 PostgreSQL 버전 12 이상에서 사용할 수 있습니다.

  인덱스를 우회하면 일관되지 않은 인덱스의 vacuum 프로세스를 건너뛰고 랩어라운드 문제를 완화할 수 있습니다. 그러나 이렇게 해도 기본 유효하지 않은 페이지 문제는 해결되지 않습니다. 유효하지 않은 페이지 문제를 완전히 해결하려면 인덱스를 다시 구축해야 합니다.

## 매우 높은 트랜잭션 속도
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.High_transaction_rate"></a>

PostgreSQL에서 높은 트랜잭션 속도는 autovacuum의 성능에 상당한 영향을 미쳐 데드 튜플의 정리가 느려지고 트랜잭션 ID 랩어라운드 위험이 증가할 수 있습니다. 두 기간의 `max(age(datfrozenxid))` 차이(일반적으로 초당)를 측정하여 트랜잭션 속도를 모니터링할 수 있습니다. 또한 RDS 성능 개선 도우미의 다음 카운터 지표를 사용하여 총 트랜잭션 수인 트랜잭션 속도(xact\$1commit과 xact\$1rollback의 합계)를 측정할 수 있습니다.


|  카운터  |  유형  |  Unit  |  지표  | 
| --- | --- | --- | --- | 
|  xact\$1commit  |  트랜잭션  |  초당 커밋 수  |  db.Transactions.xact\$1commit  | 
|  xact\$1rollback  |  트랜잭션  |  초당 롤백 수  |  db.Transactions.xact\$1rollback  | 

빠른 증가는 트랜잭션 로드가 높음을 나타내며, 이는 autovacuum에 부담을 주어 팽창, 잠금 경합 및 잠재적 성능 문제를 일으킬 수 있습니다. 이는 다음과 같은 몇 가지 방법으로 autovacuum 프로세스에 부정적인 영향을 미칠 수 있습니다.
+ **테이블 활동:** Vacuum 처리 중인 특정 테이블에 대량의 트랜잭션이 발생하여 지연이 발생할 수 있습니다.
+ **시스템 리소스:** 전체 시스템에 과부하가 발생하여 autovacuum이 효율적으로 작동하는 데 필요한 리소스에 액세스하기 어려울 수 있습니다.

Autovacuum이 더 효과적으로 작동하고 작업을 따라잡을 수 있도록 하려면 다음 전략을 고려하세요.

1. 가능하면 트랜잭션 속도를 줄입니다. 가능한 경우 유사한 트랜잭션을 배치 처리하거나 그룹화하는 것을 고려합니다.

1. 사용량이 적은 시간에 야간, 주간 또는 격주로 수동 `VACUUM FREEZE` 작업을 사용하여 자주 업데이트되는 테이블을 타게팅합니다.

1. 인스턴스 클래스를 스케일 업하여 높은 트랜잭션 볼륨과 autovacuum을 처리할 수 있도록 더 많은 시스템 리소스를 할당하는 것을 고려합니다.

# RDS for PostgreSQL의 vacuum 성능 문제 해결
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Performance"></a>

이 섹션에서는 느린 vacuum 성능에 영향을 미치는 요인과 이러한 문제를 해결하는 방법을 설명합니다.

**Topics**
+ [큰 인덱스 vacuum](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Large_indexes)
+ [테이블 또는 데이터베이스가 너무 많아 vacuum 작업을 할 수 없음](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Multiple_tables)
+ [공격적 vacuum(랩어라운드 방지용) 실행 중](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Aggressive_vacuum)

## 큰 인덱스 vacuum
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Large_indexes"></a>

VACUUM은 초기화, 힙 스캔, 인덱스 및 힙 vacuum, 인덱스 정리, 힙 잘라내기 및 최종 정리와 같은 순차적 단계를 거칩니다. 힙 스캔 중에 프로세스는 페이지를 정리하고 조각 모음을 하여 고정합니다. 힙 스캔이 완료되면 VACUUM은 인덱스를 정리하고 빈 페이지를 운영 체제로 반환하며 빈 공간 맵 vacuum 및 통계 업데이트와 같은 최종 정리 작업을 수행합니다.

인덱스를 vacuum할 때 `maintenance_work_mem`(또는 `autovacuum_work_mem`)이 인덱스를 처리하기에 충분하지 않은 경우 여러 번 전달해야 할 수 있습니다. PostgreSQL 16 이하에서는 데드 튜플 ID 저장을 위한 1GB 메모리 제한이 있어 큰 인덱스에서는 여러 번의 전달이 강제될 때가 많았습니다. PostgreSQL 17에는 단일 할당 배열을 사용하는 대신 메모리를 동적으로 할당하는 `TidStore`가 도입되었습니다. 이렇게 하면 1GB 제약이 제거되고, 메모리를 더 효율적으로 사용하며, 인덱스당 여러 인덱스 스캔의 필요성이 줄어듭니다.

사용 가능한 메모리가 전체 인덱스 처리를 한 번에 수용할 수 없는 경우에도 큰 인덱스는 PostgreSQL 17에서 여러 번 전달해야 할 수 있습니다. 일반적으로 큰 인덱스에는 여러 번 전달해야 하는 데드 튜플이 더 많이 포함되어 있습니다.

**느린 vacuum 작업 탐지**

`postgres_get_av_diag()` 함수는 메모리 부족으로 인해 vacuum 작업이 느리게 실행되는 시기를 탐지할 수 있습니다. 이 함수에 대한 자세한 내용은 [RDS for PostgreSQL에 자동 정리 모니터링 및 진단 도구 설치](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Installation.md) 단원을 참조하십시오.

사용 가능한 메모리가 단일 패스에서 인덱스 vacuuming을 완료하기에 충분하지 않은 경우 `postgres_get_av_diag()` 함수는 다음 알림을 발행합니다.

**`rds_tools` 1.8**

```
NOTICE: Your database is currently running aggressive vacuum to prevent wraparound and it might be slow.
```

```
NOTICE: The current setting of autovacuum_work_mem is "XXX" and might not be sufficient. Consider increasing the setting, and if necessary, scaling up the Amazon RDS instance class for more memory. 
        Additionally, review the possibility of manual vacuum with exclusion of indexes using (VACUUM (INDEX_CLEANUP FALSE, VERBOSE TRUE) table_name;).
```

**`rds_tools` 1.9**

```
NOTICE: Your database is currently running aggressive vacuum to prevent wraparound and it might be slow.
```

```
NOTICE: The current setting of autovacuum_work_mem is XX might not be sufficient. Consider increasing the setting to XXX, and if necessary, scaling up the RDS instance class for more 
        memory. The suggested value is an estimate based on the current number of dead tuples for the table being vacuumed, which might not fully reflect the latest state. Additionally, review the possibility of manual 
        vacuum with exclusion of indexes using (VACUUM (INDEX_CLEANUP FALSE, VERBOSE TRUE) table_name;). For more information, see 
        [Working with PostgreSQL autovacuum in the Amazon Amazon RDS User Guide](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Autovacuum.html)
        .
```

**참고**  
이 `postgres_get_av_diag()` 함수는 인덱스 vacuum 작업에 필요한 메모리의 양을 추정하기 위해 `pg_stat_all_tables.n_dead_tup`에 의존합니다.

`postgres_get_av_diag()` 함수가 `autovacuum_work_mem` 부족으로 인해 여러 인덱스 스캔이 필요한 느린 vacuum 작업을 식별하면 다음 메시지가 생성됩니다.

```
NOTICE: Your vacuum is performing multiple index scans due to insufficient autovacuum_work_mem:XXX for index vacuuming. 
        For more information, see [Working with PostgreSQL autovacuum in the Amazon Amazon RDS User Guide](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Autovacuum.html).
```

**지침**

수동 `VACUUM FREEZE`를 사용해 다음 해결 방법을 적용하여 테이블 고정의 속도를 높일 수 있습니다.

**Vacuum 작업을 위한 메모리 증가**

`postgres_get_av_diag()` 함수에서 제안한 대로 인스턴스 수준에서 잠재적 메모리 제약을 해결하기 위해 `autovacuum_work_mem` 파라미터를 늘리는 것이 좋습니다. `autovacuum_work_mem`은 동적 파라미터이지만 새 메모리 설정이 적용되려면 autovacuum 대몬이 작업자를 다시 시작해야 합니다. 이를 수행하는 방법은 다음과 같습니다.

1. 새 설정이 있는지 확인합니다.

1. 현재 autovacuum을 실행 중인 프로세스를 종료합니다.

이 접근 방식을 사용하면 조정된 메모리 할당이 새 autovacuum 작업에 적용됩니다.

보다 즉각적인 결과를 얻으려면 세션 내에서 `maintenance_work_mem` 설정이 증가된 `VACUUM FREEZE` 작업을 수동으로 수행하는 것을 고려하세요.

```
SET maintenance_work_mem TO '1GB';
VACUUM FREEZE VERBOSE table_name;
```

Amazon RDS를 사용하고 있고 `maintenance_work_mem` 또는 `autovacuum_work_mem`에 대해 더 높은 값을 지원하는 데 추가 메모리가 필요한 경우 메모리가 더 많은 인스턴스 클래스로 업그레이드하는 것을 고려해 보세요. 이를 통해 수동 및 자동 vacuum 작업을 모두 개선하는 데 필요한 리소스를 제공하여 전반적인 vacuum 및 데이터베이스 성능을 개선할 수 있습니다.

**INDEX\$1CLEANUP 비활성화**

PostgreSQL 버전 12 이상의 수동 `VACUUM`에서는 인덱스 정리 단계를 건너뛸 수 있고, PostgreSQL 버전 14 이상의 긴급 autovacuum에서는 [https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-VACUUM-FAILSAFE-AGE](https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-VACUUM-FAILSAFE-AGE) 파라미터를 기반으로 자동으로 이 작업을 수행합니다.

**주의**  
인덱스 정리를 건너뛰면 인덱스 팽창이 발생하여 쿼리 성능에 부정적인 영향을 미칠 수 있습니다. 이를 완화하려면 영향을 받는 인덱스를 유지 관리 기간 동안 다시 인덱싱하거나 vacuum하는 것이 좋습니다.

큰 인덱스 처리에 대한 추가 지침은 [대용량 인덱스를 사용하여 autovacuum 관리](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.LargeIndexes.md)의 설명서를 참조하세요.

**병렬 인덱스 vacuum 작업**

PostgreSQL 13부터 인덱스는 각 인덱스에 하나의 vacuum 작업자 프로세스가 할당된 수동 `VACUUM`을 사용하여 기본적으로 병렬로 vacuum 및 정리가 가능합니다. 그러나 vacuum 작업이 병렬 실행에 적합한지 PostgreSQL이 확인하려면 다음과 같은 특정 기준을 충족해야 합니다.
+ 인덱스가 최소 2개 있어야 합니다.
+ `max_parallel_maintenance_workers` 파라미터 값을 최소 2로 설정합니다.
+ 인덱스 크기는 `min_parallel_index_scan_size` 한도를 초과해야 하며, 기본값은 512KB입니다.

Amazon RDS 인스턴스에서 사용할 수 vCPU의 수와 테이블의 인덱스 수에 따라 `max_parallel_maintenance_workers` 설정을 조정하여 vacuum 작업 처리 시간을 최적화할 수 있습니다.

자세한 내용은 [Parallel vacuuming in Amazon RDS for PostgreSQL and Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/parallel-vacuuming-in-amazon-rds-for-postgresql-and-amazon-aurora-postgresql/)을 참조하세요.

## 테이블 또는 데이터베이스가 너무 많아 vacuum 작업을 할 수 없음
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Multiple_tables"></a>

PostgreSQL의 [The Autovacuum Daemon](https://www.postgresql.org/docs/current/routine-vacuuming.html#AUTOVACUUM') 설명서에서 언급한 것처럼 autovacuum 대몬은 여러 프로세스를 통해 작동합니다. 여기에는 시스템 내 각 데이터베이스에 대해 autovacuum 작업자 프로세스를 시작하는 영구 autovacuum 런처가 포함됩니다. 런처는 데이터베이스당 약 `autovacuum_naptime`초마다 이러한 작업자가 시작하도록 일정을 예약합니다.

데이터베이스가 'N'개이면 새 작업자가 대략 [`autovacuum_naptime`/N초]마다 시작합니다. 그러나 총 동시 작업자 수는 `autovacuum_max_workers` 설정에 따라 제한됩니다. Vacuum 작업이 필요한 데이터베이스 또는 테이블 수가 이 한도를 초과하는 경우 작업자를 사용할 수 있게 되는 즉시 다음 데이터베이스 또는 테이블이 처리됩니다.

많은 대형 테이블 또는 데이터베이스에서 동시에 vacuum 작업이 필요한 경우 사용 가능한 모든 autovacuum 작업자가 장기간 점유되어 다른 테이블 및 데이터베이스에 대한 유지 관리가 지연될 수 있습니다. 트랜잭션 속도가 높은 환경에서는 이 병목 현상이 빠르게 에스컬레이션되어 Amazon RDS 인스턴스 내에서 vacuum 랩어라운드 문제가 발생할 수 있습니다.

`postgres_get_av_diag()`가 많은 수의 테이블 또는 데이터베이스를 감지하면 다음과 같은 권장 사항을 제공합니다.

```
NOTICE: Your database is currently running aggressive vacuum to prevent wraparound and it might be slow.
```

```
NOTICE: The current setting of autovacuum_max_workers:3 might not be sufficient. Consider increasing the setting and, if necessary, consider scaling up the Amazon RDS instance class for more workers.
```

**지침**

**autovacuum\$1max\$1workers 증가**

Vacuum 작업의 속도를 높이기 위해 더 많은 동시 autovacuum 작업자를 허용하도록 `autovacuum_max_workers` 파라미터를 조정하는 것이 좋습니다. 성능 병목 현상이 지속되면 Amazon RDS 인스턴스를 더 많은 vCPU가 있는 클래스로 스케일 업하는 것이 좋습니다. 이렇게 하면 병렬 처리 기능을 더욱 개선할 수 있습니다.

## 공격적 vacuum(랩어라운드 방지용) 실행 중
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Aggressive_vacuum"></a>

PostgreSQL의 데이터베이스(MaximumUsedTransactionIDs) 연령은 공격적 vacuum(랩어라운드 방지용)이 성공적으로 완료될 때만 감소합니다. 이 vacuum 작업이 완료될 때까지 트랜잭션 속도에 따라 연령이 계속 증가합니다.

`postgres_get_av_diag()` 함수는 공격적인 vacuum을 감지하면 다음 `NOTICE`를 생성합니다. 그러나 vacuum의 활성 상태가 최소 2분간 지속된 후에만 이 출력이 트리거됩니다.

```
NOTICE: Your database is currently running aggressive vacuum to prevent wraparound, monitor autovacuum performance.
```

공격적 vacuum에 대한 자세한 내용은 [When an aggressive vacuum is already running](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.NOTICE.md) 섹션을 참조하세요.

다음 쿼리를 사용하여 공격적인 vacuum이 진행 중인지 확인할 수 있습니다.

```
SELECT
    a.xact_start AS start_time,
    v.datname "database",
    a.query,
    a.wait_event,
    v.pid,
    v.phase,
    v.relid::regclass,
    pg_size_pretty(pg_relation_size(v.relid)) AS heap_size,
    (
        SELECT
            string_agg(pg_size_pretty(pg_relation_size(i.indexrelid)) || ':' || i.indexrelid::regclass || chr(10), ', ')
        FROM
            pg_index i
        WHERE
            i.indrelid = v.relid
    ) AS index_sizes,
    trunc(v.heap_blks_scanned * 100 / NULLIF(v.heap_blks_total, 0)) AS step1_scan_pct,
    v.index_vacuum_count || '/' || (
        SELECT
            count(*)
        FROM
            pg_index i
        WHERE
            i.indrelid = v.relid
    ) AS step2_vacuum_indexes,
    trunc(v.heap_blks_vacuumed * 100 / NULLIF(v.heap_blks_total, 0)) AS step3_vacuum_pct,
    age(CURRENT_TIMESTAMP, a.xact_start) AS total_time_spent_sofar
FROM
    pg_stat_activity a
    INNER JOIN pg_stat_progress_vacuum v ON v.pid = a.pid;
```

출력의 쿼리 열을 확인하여 공격적인 vacuum(랩어라운드 방지용)인지 확인할 수 있습니다. '랩어라운드 방지용'이라는 문구는 공격적인 vacuum임을 나타냅니다.

```
query                  | autovacuum: VACUUM public.t3 (to prevent wraparound)
```

예를 들어, 트랜잭션 연령이 10억인 블로커가 있고 동일한 트랜잭션 연령에서 랩어라운드 방지용으로 공격적인 vacuum이 필요한 테이블이 있다고 가정해 보겠습니다. 또한 트랜잭션 연령이 7억 5,000만인 또 다른 블로커가 있습니다. 트랜잭션 연령이 1억인 블로커를 정리한 후에 트랜잭션 연령이 7억 5,000만으로 즉시 줄어들지 않습니다. 공격적인 vacuum이 필요한 테이블 또는 연령이 7억 5,000만이 넘는 트랜잭션이 완료될 때까지 트랜잭션 연령이 높게 유지됩니다. 이 기간 동안 PostgreSQL 클러스터의 트랜잭션 연령이 계속 증가합니다. Vacuum 프로세스가 완료되면 트랜잭션 연령이 7억 5,000만으로 감소하지만 추가 vacuum 작업이 완료될 때까지 다시 증가하기 시작합니다. 이 주기는 이러한 조건이 지속되는 한, 트랜잭션 연령이 결국 `autovacuum_freeze_max_age`에서 지정된 Amazon RDS 인스턴스에 대해 구성된 수준으로 떨어질 때까지 계속됩니다.

# RDS for PostgreSQL의 NOTICE 메시지 설명
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.NOTICE"></a>

 `postgres_get_av_diag()` 함수는 다음 NOTICE 메시지를 제공합니다.

**연령이 모니터링 임곗값에 아직 도달하지 않은 경우**  
`postgres_get_av_diag()`가 블로커를 식별하기 위한 모니터링 임곗값은 기본적으로 5억 개의 트랜잭션입니다. `postgres_get_av_diag()`가 다음 NOTICE를 생성하면 트랜잭션 연령이 아직이 임곗값에 도달하지 않았음을 나타냅니다.  

```
NOTICE: postgres_get_av_diag() checks for blockers that prevent aggressive vacuums only, it does so only after exceeding dvb_threshold which is 500,000,000 and age of this PostgreSQL cluster is currently at 2.
```

**연령이 가장 많은 트랜잭션 ID를 가진 데이터베이스에 연결되지 않음**  
`postgres_get_av_diag()` 함수는 연령이 가장 많은 트랜잭션 ID를 가진 데이터베이스에 연결할 때 가장 정확한 출력을 제공합니다. `postgres_get_av_diag()`에서 보고한 연령이 가장 많은 트랜잭션 ID를 가진 데이터베이스는 사용자의 경우 'my\$1database'와 다릅니다. 올바른 데이터베이스에 연결되지 않은 경우 다 NOTICE가 생성됩니다.  

```
NOTICE: You are not connected to the database with the age of oldest transaction ID. Connect to my_database database and run postgres_get_av_diag() for accurate reporting.
```
연령이 가장 많은 트랜잭션을 가진 데이터베이스에 연결하는 것은 다음과 같은 이유로 중요합니다.  
+ **임시 테이블 블로커 식별:** 임시 테이블의 메타데이터는 각 데이터베이스마다 다르기 때문에 일반적으로 테이블이 만들어진 데이터베이스에서 찾을 수 있습니다. 그러나 임시 테이블이 최상위 블로커이고 수명이 가장 많은 트랜잭션을 가진 데이터베이스에 있는 경우 이는 오해의 소지가 있을 수 있습니다. 올바른 데이터베이스에 연결하면 임시 테이블 블로커를 정확하게 식별할 수 있습니다.
+ **느린 vacuum 진단:** 인덱스 메타데이터 및 테이블 수 정보는 데이터베이스별로 다르며 느린 vacuum 문제를 진단하는 데 필요합니다.

**연령을 기준으로 가장 오래된 트랜잭션을 가진 데이터베이스가 rdsadmin 또는 template0 데이터베이스임**  
경우에 따라 `rdsadmin` 또는 `template0` 데이터베이스가 연령이 가장 많은 트랜잭션 ID를 가진 데이터베이스로 식별될 수 있습니다. 이 경우 `postgres_get_av_diag()`는 다음 NOTICE를 발행합니다.  

```
NOTICE: The database with the age of oldest transaction ID is rdsadmin or template0, reach out to support if the reported blocker is in rdsadmin or template0.
```
나열된 블로커가 이 두 데이터베이스 중 하나에서 시작되지 않는지 확인합니다. `rdsadmin` 또는 `template0`에 블로커가 있는 것으로 보고되는 경우 이러한 데이터베이스는 사용자가 액세스할 수 없으며 개입이 필요하므로 지원팀에 문의하세요.  
`rdsadmin` 또는 `template0` 데이터베이스가 최상위 블로커를 포함할 가능성은 매우 낮습니다.

**공격적 vacuum이 이미 실행 중인 경우**  
`postgres_get_av_diag()` 함수는 공격적인 vacuum 프로세스가 실행 중일 때 보고하도록 설계되었지만, vacuum이 최소 1분 동안 활성 상태인 경우에만 이 출력을 트리거합니다. 이러한 의도적인 지연은 오탐지의 가능성을 줄이는 데 도움이 됩니다. 이 함수는 대기함으로써 효과적이고 중요한 vacuum만 보고되도록 하므로 vacuum 활동을 보다 정확하고 안정적으로 모니터링할 수 있습니다.  
`postgres_get_av_diag()` 함수는 진행 중인 공격적인 vacuum이 하나 이상인 것을 감지하면 다음 NOTICE를 생성합니다.  

```
NOTICE: Your database is currently running aggressive vacuum to prevent wraparound, monitor autovacuum performance.
```
NOTICE에 표시된 대로 vacuum의 성능을 계속 모니터링합니다. 공격적 vacuum에 대한 자세한 내용은 [공격적 vacuum(랩어라운드 방지용) 실행 중](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Performance.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Aggressive_vacuum) 섹션을 참조하세요.

**Autovacuum이 꺼져 있는 경우**  
데이터베이스 인스턴스에서 autovacuum이 비활성화된 경우 `postgres_get_av_diag()` 함수는 다음 NOTICE를 생성합니다.  

```
NOTICE: Autovacuum is OFF, we strongly recommend to enable it, no restart is necessary.
```
자동 정리는 원활한 데이터베이스 작업을 보장하는 RDS for PostgreSQL DB 인스턴스의 중요한 기능입니다. 오래된 행 버전을 자동으로 제거하고, 스토리지 공간을 회수하고, 테이블 팽창을 방지하여 테이블과 인덱스를 효율적으로 유지함으로써 최적의 성능을 발휘하도록 합니다. 또한 Amazon RDS 인스턴스에서 트랜잭션을 중지할 수 있는 트랜잭션 ID 랩어라운드를 방지합니다. Autovacuum을 비활성화하면 데이터베이스 성능과 안정성이 장기적으로 저하될 수 있습니다. 항상 켜두는 것이 좋습니다. 자세한 내용은 [Understanding autovacuum in RDS for PostgreSQL environments](https://aws.amazon.com/blogs/database/understanding-autovacuum-in-amazon-rds-for-postgresql-environments/)를 참조하세요.  
Autovacuum을 끄더라도 공격적인 vacuum이 중지되지 않습니다. 테이블이 `autovacuum_freeze_max_age` 임곗값에 도달하면 여전히 공격적 vacuum이 발생합니다.

**남은 트랜잭션 수가 매우 적음**  
`postgres_get_av_diag()` 함수는 랩어라운드 vacuum이 임박하면 다음 NOTICE를 생성합니다. 이 NOTICE는 Amazon RDS 인스턴스가 잠재적으로 새 트랜잭션을 거부하기까지 1억 개의 트랜잭션이 남았을 때 발행됩니다.  

```
WARNING: Number of transactions remaining is critically low, resolve issues with autovacuum or perform manual VACUUM FREEZE before your instance stops accepting transactions.
```
데이터베이스 가동 중지 시간을 방지하려면 즉각적인 조치가 필요합니다. Vacuum 작업을 면밀히 모니터링하고 영향을 받는 데이터베이스에서 `VACUUM FREEZE`를 수동으로 시작하여 트랜잭션 실패를 방지해야 합니다.