

# Amazon RDS for PostgreSQL의 일반적인 DBA 태스크
<a name="Appendix.PostgreSQL.CommonDBATasks"></a>

데이터베이스 관리자(DBA)는 Amazon RDS for PostgreSQL DB 인스턴스를 관리할 때 다양한 작업을 수행합니다. PostgreSQL을 이미 익숙하게 사용하는 DBA라면 하드웨어에서 PostgreSQL을 실행하는 것과 RDS for PostgreSQL을 실행하는 것 사이의 중요한 차이점을 알고 있어야 합니다. 예를 들어 이는 관리형 서비스이므로, Amazon RDS에서 DB 인스턴스에 대한 shell 액세스를 허용하지 않습니다. 즉, `pg_hba.conf` 및 다른 구성 파일에 직접 액세스할 수 없습니다. RDS for PostgreSQL의 경우 일반적으로 온프레미스 인스턴스의 PostgreSQL 구성 파일을 변경하면 RDS for PostgreSQL DB 인스턴스와 연결된 사용자 지정 DB 파라미터 그룹도 변경됩니다. 자세한 내용은 [Amazon RDS의 파라미터 그룹](USER_WorkingWithParamGroups.md) 섹션을 참조하세요.

또한 온프레미스 PostgreSQL 인스턴스와 동일한 방식으로 로그 파일에 액세스할 수 없습니다. 로깅에 대해 자세히 알아보려면 [ RDS for PostgreSQL 데이터베이스 로그 파일](USER_LogAccess.Concepts.PostgreSQL.md) 섹션을 참조하세요.

다른 예로, PostgreSQL `superuser` 계정에 액세스할 권한이 없습니다. RDS for PostgreSQL에서 `rds_superuser` 역할은 가장 높은 권한을 가진 역할이며 설정 시 `postgres`에 부여됩니다. PostgreSQL 온프레미스 사용에 익숙하든, RDS for PostgreSQL을 처음 사용하든 관계없이 `rds_superuser` 역할 및 역할, 사용자, 그룹, 권한으로 작업하는 방식을 이해하는 것이 좋습니다. 자세한 내용은 [PostgreSQL 역할 및 권한 이해](Appendix.PostgreSQL.CommonDBATasks.Roles.md) 섹션을 참조하세요.

다음은 RDS for PostgreSQL의 일반적인 DBA 태스크 일부입니다.

**Topics**
+ [RDS for PostgreSQL에서 지원되는 데이터 정렬입니다.](PostgreSQL-Collations.md)
+ [PostgreSQL 역할 및 권한 이해](Appendix.PostgreSQL.CommonDBATasks.Roles.md)
+ [PostgreSQL에서 연결 중단 처리](Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling.md)
+ [Amazon RDS for PostgreSQL에서 PostgreSQL 자동 정리 사용](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.md)
+ [Amazon RDS for PostgreSQL에서 다수의 객체 관리](PostgreSQL.HighObjectCount.md)
+ [Amazon RDS for PostgreSQL에서 TOAST OID 경합 관리](Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.md)
+ [RDS for PostgreSQL에서 지원되는 로깅 메커니즘 작업](#Appendix.PostgreSQL.CommonDBATasks.Auditing)
+ [PostgreSQL을 사용한 임시 파일 관리](PostgreSQL.ManagingTempFiles.md)
+ [pgBadger를 사용한 PostgreSQL의 로그 분석](#Appendix.PostgreSQL.CommonDBATasks.Badger)
+ [PGSnapper를 사용하여 PostgreSQL 모니터링](#Appendix.PostgreSQL.CommonDBATasks.Snapper)
+ [RDS for PostgreSQL에서 사용자 지정 캐스트 관리](PostgreSQL.CustomCasts.md)
+ [RDS for PostgreSQL의 병렬 쿼리 모범 사례](PostgreSQL.ParallelQueries.md)
+ [RDS for PostgreSQL DB 인스턴스에 파라미터로 작업](Appendix.PostgreSQL.CommonDBATasks.Parameters.md)

# RDS for PostgreSQL에서 지원되는 데이터 정렬입니다.
<a name="PostgreSQL-Collations"></a>

데이터 정렬은 데이터베이스에 저장된 문자열을 정렬하고 비교하는 방법을 결정하는 일련의 규칙입니다. 데이터 정렬은 컴퓨터 시스템에서 기본적인 역할을 하며 운영 체제의 일부로 포함됩니다. 새 문자가 언어에 추가되거나 순서 지정 규칙이 변경되면 시간이 지남에 따라 데이터 정렬이 변경됩니다.

데이터 정렬 라이브러리는 데이터 정렬에 대한 특정 규칙 및 알고리즘을 정의합니다. PostgreSQL에서 가장 많이 사용되는 데이터 정렬 라이브러리는 GNU C(glibc) 및 유니코드용 국제화 구성 요소(ICU)입니다. 기본적으로 RDS for PostgreSQL은 멀티바이트 문자 시퀀스에 대한 유니코드 문자 정렬 순서를 포함하는 glibc 데이터 정렬을 사용합니다.

새로운 RDS for PostgreSQL의 DB 인스턴스를 만들면 운영 체제에서 사용 가능한 데이터 정렬을 확인합니다. `CREATE DATABASE` 명령의 PostgreSQL 파라미터인 `LC_COLLATE` 및 `LC_CTYPE`은 해당 데이터베이스의 기본 데이터 정렬로 사용되는 데이터 정렬을 지정하는 데 사용됩니다. 또는 `CREATE DATABASE`의 `LOCALE` 파라미터를 사용하여 이러한 파라미터를 설정할 수도 있습니다. 이는 데이터베이스의 문자열에 대한 기본 데이터 정렬과 문자를 문자, 숫자 또는 기호로 분류하는 규칙을 결정합니다. 열, 색인 또는 쿼리에 사용할 데이터 정렬을 선택할 수도 있습니다.

RDS for PostgreSQL은 데이터 정렬 지원을 위해 운영 체제의 glibc 라이브러리를 사용합니다. RDS for PostgreSQL 인스턴스는 최신 버전의 운영 체제로 정기적으로 업데이트됩니다. 이러한 업데이트에는 glibc 라이브러리의 최신 버전도 포함되는 경우가 있습니다. 드물게 최신 버전의 glibc에서는 일부 문자의 정렬 순서 또는 데이터 정렬이 변경되어 데이터가 다르게 정렬되거나 잘못된 색인 항목이 생성될 수 있습니다. 업데이트 중에 데이터 정렬의 정렬 순서 문제가 발견되면 색인을 다시 작성해야 할 수 있습니다.

glibc 업데이트의 영향을 줄이기 위해 RDS for PostgreSQL에는 이제 독립적인 기본 데이터 정렬 라이브러리가 포함되어 있습니다. 이 데이터 정렬 라이브러리는 RDS for PostgreSQL 14.6, 13.9, 12.13, 11.18, 10.23 및 최신 마이너 버전 릴리스에서 사용할 수 있습니다. glibc 2.26-59.amzn2와 호환되며 정렬 순서 안정성을 제공하여 잘못된 쿼리 결과가 나오지 않도록 방지합니다.

# PostgreSQL 역할 및 권한 이해
<a name="Appendix.PostgreSQL.CommonDBATasks.Roles"></a>

AWS Management Console을 사용하여 RDS for PostgreSQL DB 인스턴스를 만들면 관리자 계정이 동시에 생성됩니다. 기본적으로 해당 이름은 다음 스크린샷에 나와 있는 것처럼 `postgres`입니다.

![\[데이터베이스 생성(Create database) 페이지의 보안 인증에 대한 기본 로그인 ID는 postgres입니다.\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/images/default-login-identity-apg-rpg.png)


기본값(`postgres`)을 그대로 사용하지 않고 다른 이름을 선택할 수 있습니다. 이 경우 선택한 이름은 문자로 시작해야 하며 영숫자 1\$116자 사이어야 합니다. 단순하게 하기 위해 이 안내서 전체에서 기본 사용자 계정을 기본값(`postgres`)으로 참조합니다.

AWS Management Console 대신 `create-db-instance` AWS CLI를 사용하는 경우 명령에서 `master-username` 파라미터로 이름을 전달하여 이름을 생성합니다. 자세한 내용은 [Amazon RDS DB 인스턴스 생성](USER_CreateDBInstance.md) 단원을 참조하세요. 

AWS Management Console, AWS CLI 또는 Amazon RDS API를 사용하든, 기본 `postgres` 이름을 사용하든, 다른 이름을 선택하든 관계없이 첫 번째 데이터베이스 사용자 계정은 `rds_superuser` 그룹의 멤버이며 `rds_superuser` 권한을 가집니다.

**Topics**
+ [rds\$1superuser 역할 이해](Appendix.PostgreSQL.CommonDBATasks.Roles.rds_superuser.md)
+ [PostgreSQL 데이터베이스에 대한 사용자 액세스 제어](Appendix.PostgreSQL.CommonDBATasks.Access.md)
+ [사용자 암호 관리 위임 및 제어](Appendix.PostgreSQL.CommonDBATasks.RestrictPasswordMgmt.md)
+ [SCRAM for PostgreSQL 암호 암호화 사용](PostgreSQL_Password_Encryption_configuration.md)

# rds\$1superuser 역할 이해
<a name="Appendix.PostgreSQL.CommonDBATasks.Roles.rds_superuser"></a>

PostgreSQL에서는 *역할*로 데이터베이스의 다양한 객체에 대해 그룹 또는 사용자에게 부여된 사용자, 그룹 또는 특정 권한 집합을 정의할 수 있습니다. `CREATE USER` 및 `CREATE GROUP`에 대한 PostgreSQL 명령은 데이터베이스 사용자를 구분하기 위한 특정 속성을 가진 보다 일반적인 `CREATE ROLE`로 대체되었습니다. 데이터베이스 사용자는 LOGIN 권한을 가진 역할로 간주할 수 있습니다.

**참고**  
`CREATE USER` 및 `CREATE GROUP` 명령을 계속 사용할 수 있습니다. 자세한 내용은 PostgreSQL 설명서에서 [데이터베이스 역할](https://www.postgresql.org/docs/current/user-manag.html)을 참조하세요.

`postgres` 사용자는 RDS for PostgreSQL DB 인스턴스에서 가장 높은 권한을 지닌 데이터베이스 사용자입니다. 이는 다음 `CREATE ROLE` 문으로 정의되는 특성을 가지고 있습니다.

```
CREATE ROLE postgres WITH LOGIN NOSUPERUSER INHERIT CREATEDB CREATEROLE NOREPLICATION VALID UNTIL 'infinity'
```

속성 `NOSUPERUSER`, `NOREPLICATION`, `INHERIT` 및 `VALID UNTIL 'infinity'`는 별도로 지정하지 않는 한 CREATE ROLE의 기본 옵션입니다.

기본적으로 `postgres`에는 `rds_superuser` 역할에 부여된 권한과 역할 및 데이터베이스를 생성할 수 있는 권한이 있습니다. `rds_superuser` 역할이 있으면 `postgres` 사용자는 다음과 같은 작업을 할 수 있습니다.
+ Amazon RDS에서 사용할 수 있는 확장 기능을 추가합니다. 자세한 내용은 [Amazon RDS for PostgreSQL에서 지원되는 PostgreSQL 기능 작업](PostgreSQL.Concepts.General.FeatureSupport.md) 
+ 사용자에 대한 역할을 생성하고 사용자에게 권한을 부여합니다. 자세한 내용은 PostgreSQL 설명서에서 [CREATE ROLE](https://www.postgresql.org/docs/current/sql-createrole.html) 및 [GRANT](https://www.postgresql.org/docs/14/sql-grant.html)를 참조하세요.
+ 데이터베이스를 생성합니다. 자세한 내용은 PostgreSQL 설명서에서 [CREATE DATABASE](https://www.postgresql.org/docs/14/sql-createdatabase.html)를 참조하세요.
+ 이러한 권한이 없는 사용자 역할에 `rds_superuser` 권한을 부여하고 필요에 따라 권한을 회수합니다. 이 역할은 수퍼유저 태스크를 수행하는 사용자에게만 부여하는 것이 좋습니다. 즉, 데이터베이스 관리자(DBA) 또는 시스템 관리자에게 이 역할을 부여할 수 있습니다.
+ `rds_superuser` 역할이 없는 데이터베이스 사용자에게 `rds_replication` 역할을 부여(회수)합니다.
+ `rds_superuser` 역할이 없는 데이터베이스 사용자에게 `rds_password` 역할을 부여(회수)합니다.
+ `pg_stat_activity` 보기를 사용하여 모든 데이터베이스 연결에 대한 상태 정보를 가져옵니다. 필요한 경우 `rds_superuser`는 `pg_terminate_backend` 또는 `pg_cancel_backend`를 사용하여 연결을 중지할 수 있습니다.

`CREATE ROLE postgres...` 문에서 `postgres` 사용자 역할이 특히 PostgreSQL `superuser` 권한을 허용하지 않음을 알 수 있습니다. RDS for PostgreSQL은 관리형 서비스이므로 호스트 OS에 액세스할 수 없으며, PostgreSQL `superuser` 계정을 사용하여 연결할 수 없습니다. 독립 실행형 PostgreSQL에 대한 `superuser` 액세스 권한이 필요한 대부분의 태스크는 Amazon RDS에서 자동으로 관리됩니다.

권한 부여에 대한 자세한 내용은 PostgreSQL 설명서에서 [GRANT](http://www.postgresql.org/docs/current/sql-grant.html)를 참조하세요.

`rds_superuser` 역할은 에서 *미리 정의된* 여러 역할 중 하나입니다. RDS for PostgreSQL DB 인스턴스 

**참고**  
PostgreSQL 13 및 이전 릴리스에서는 *미리 정의된* 역할을 *기본* 역할이라고 합니다.

다음 목록에서 새로운 에 대해 자동으로 생성되는 미리 정의된 다른 역할 중 일부를 확인할 수 있습니다. RDS for PostgreSQL DB 인스턴스 미리 정의된 역할 및 권한은 변경할 수 없습니다. 미리 정의된 역할에 대한 권한은 삭제하거나 이름을 바꾸거나 수정할 수 없습니다. 이를 시도할 시에는 오류가 발생합니다.
+ **rds\$1password** - 데이터베이스 사용자를 대상으로 암호를 변경하고 암호 제약 조건을 설정할 수 있는 역할입니다. `rds_superuser` 역할에는 기본적으로 이 역할이 부여되며, 이 역할을 통해 데이터베이스 사용자에게 역할을 부여할 수 있습니다. 자세한 내용은 [PostgreSQL 데이터베이스에 대한 사용자 액세스 제어PostgreSQL에 대한 사용자 액세스 제어](Appendix.PostgreSQL.CommonDBATasks.Access.md) 섹션을 참조하세요.
  + 14 이전의 RDS for PostgreSQL 버전에서 `rds_password` 역할은 암호를 변경하고 데이터베이스 사용자와 `rds_superuser` 역할이 있는 사용자에 대해 암호 제한을 설정할 수 있습니다. 14 이후의 RDS for PostgreSQL 버전에서 `rds_password` 역할은 데이터베이스 사용자에 대해서만 암호를 변경하고 암호 제약 조건을 설정할 수 있습니다. `rds_superuser` 역할이 있는 사용자만 `rds_superuser` 역할을 가진 다른 사용자에게 이러한 작업을 수행할 수 있습니다.
+ **rdsadmin** - `superuser` 권한이 있는 관리자가 독립 실행형 PostgreSQL 데이터베이스에서 수행할 수 있는 많은 관리 태스크를 처리하기 위해 생성된 역할입니다. 이 역할은 RDS for PostgreSQL에서 다양한 관리 태스크에 내부적으로 사용됩니다.
+ **rdstopmgr** - 다중 AZ 배포를 지원하기 위해 Amazon RDS에서 내부적으로 사용하는 역할입니다.
+ **rds\$1reserved** – Amazon RDS에서 데이터베이스 연결을 예약하는 데 내부적으로 사용하는 역할입니다.

# 역할 및 해당 권한 보기
<a name="Appendix.PostgreSQL.CommonDBATasks.Roles.View"></a>

PostgreSQL 버전에 따라 서로 다른 명령을 사용하여 RDS for PostgreSQL DB 인스턴스에서 사전 정의된 역할과 해당 권한을 볼 수 있습니다. 사전 정의된 모든 역할을 보려면 RDS for PostgreSQL DB 인스턴스에 연결하고 `psql`을 사용하여 다음 명령을 실행할 수 있습니다.

**`psql` 15 이하 버전의 경우**

RDS for PostgreSQL DB 인스턴스에 연결하고 psql에서 `\du` 명령을 사용합니다.

```
postgres=> \du
                                                               List of roles
    Role name    |                         Attributes                         |                          Member of
-----------------+------------------------------------------------------------+------------------------------------------------------
 postgres        | Create role, Create DB                                    +| {rds_superuser}
                 | Password valid until infinity                              |
 rds_ad          | Cannot login                                               | {}
 rds_iam         | Cannot login                                               | {}
 rds_password    | Cannot login                                               | {}
 rds_replication | Cannot login                                               | {}
 rds_superuser   | Cannot login                                               | {pg_monitor,pg_signal_backend,rds_password,rds_replication}
 rdsadmin        | Superuser, Create role, Create DB, Replication, Bypass RLS+| {}
                 | Password valid until infinity                              |
```

**`psql` 16 이상 버전의 경우**

```
postgres=> \drg+
                             List of role grants
   Role name   |          Member of          |       Options       | Grantor
---------------+-----------------------------+---------------------+----------
 postgres      | rds_superuser               | INHERIT, SET        | rdsadmin
 rds_superuser | pg_checkpoint               | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | pg_monitor                  | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | pg_signal_backend           | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | pg_use_reserved_connections | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | rds_password                | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | rds_replication             | ADMIN, INHERIT, SET | rdsadmin
```

버전 종속성 없이 역할 멤버십을 확인하려면 다음 SQL 쿼리를 사용할 수 있습니다.

```
SELECT m.rolname AS "Role name", r.rolname AS "Member of"
FROM pg_catalog.pg_roles m
JOIN pg_catalog.pg_auth_members pam ON (pam.member = m.oid)
LEFT JOIN pg_catalog.pg_roles r ON (pam.roleid = r.oid)
LEFT JOIN pg_catalog.pg_roles g ON (pam.grantor = g.oid)
WHERE m.rolname !~ '^pg_'
ORDER BY 1, 2;
```

출력에서 `rds_superuser`는 데이터베이스 사용자 역할은 아니지만(로그인할 수 없음), 다른 많은 역할의 권한을 가집니다. 데이터베이스 사용자 `postgres`가 `rds_superuser` 역할의 멤버임을 알 수도 있습니다. 앞서 언급한 바와 같이 `postgres`는 Amazon RDS 콘솔 **데이터베이스 생성(Create database)** 페이지의 기본값입니다. 다른 이름을 선택한 경우 해당 이름이 대신 역할 목록에 표시됩니다.

# PostgreSQL 데이터베이스에 대한 사용자 액세스 제어
<a name="Appendix.PostgreSQL.CommonDBATasks.Access"></a>

PostgreSQL의 새 데이터베이스는 항상 모든 데이터베이스 사용자와 역할이 객체를 만들 수 있도록 허용하는 데이터베이스 `public` 스키마의 기본 권한 집합으로 생성됩니다. 이러한 권한을 통해 데이터베이스 사용자는 데이터베이스에 연결하고, 가령 연결된 동안 임시 테이블을 만들 수 있습니다.

RDS for PostgreSQL DB 인스턴스 에 생성한 데이터베이스 인스턴스에 액세스할 수 있는 사용자 권한을 보다 효과적으로 제어하려면 이러한 기본 `public` 권한을 회수하는 것이 좋습니다. 이렇게 하고 나서 다음 절차에 표시된 것처럼 데이터베이스 사용자에게 보다 세분화된 구체적인 권한을 부여하면 됩니다.

**새 데이터베이스 인스턴스에 대한 역할 및 권한을 설정하는 방법**

새로 생성한 RDS for PostgreSQL DB 인스턴스에 데이터베이스를 설정하여 여러 연구자가 사용할 수 있도록 하고, 이들 모두 데이터베이스에 대한 읽기-쓰기 액세스 권한이 필요하다고 가정합니다.

1. 다음과 같이 `psql` 또는 pgAdmin을 사용하여 RDS for PostgreSQL DB 인스턴스에 연결합니다.

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

   메시지가 표시되면 암호를 입력합니다. `psql` 클라이언트는 기본 관리 연결 데이터베이스인 `postgres=>`를 연결하고 프롬프트로 표시합니다.

1. 데이터베이스 사용자가 `public` 스키마에서 객체를 생성하지 못하도록 하려면 다음을 수행합니다.

   ```
   postgres=> REVOKE CREATE ON SCHEMA public FROM PUBLIC;
   REVOKE
   ```

1. 다음으로 새 데이터베이스 인스턴스를 생성합니다.

   ```
   postgres=> CREATE DATABASE lab_db;
   CREATE DATABASE
   ```

1. 새 데이터베이스의 `PUBLIC` 스키마에서 모든 권한을 회수합니다.

   ```
   postgres=> REVOKE ALL ON DATABASE lab_db FROM public;
   REVOKE
   ```

1. 데이터베이스 사용자를 위한 역할을 생성합니다.

   ```
   postgres=> CREATE ROLE lab_tech;
   CREATE ROLE
   ```

1. 이 역할이 있는 데이터베이스 사용자에게 데이터베이스 연결 기능을 제공합니다.

   ```
   postgres=> GRANT CONNECT ON DATABASE lab_db TO lab_tech;
   GRANT
   ```

1. `lab_tech` 역할이 있는 모든 사용자에게 이 데이터베이스에 대한 모든 권한을 부여합니다.

   ```
   postgres=> GRANT ALL PRIVILEGES ON DATABASE lab_db TO lab_tech;
   GRANT
   ```

1. 다음과 같이 데이터베이스 사용자를 생성합니다.

   ```
   postgres=> CREATE ROLE lab_user1 LOGIN PASSWORD 'change_me';
   CREATE ROLE
   postgres=> CREATE ROLE lab_user2 LOGIN PASSWORD 'change_me';
   CREATE ROLE
   ```

1. 다음과 같이 두 사용자에게 lab\$1tech 역할과 관련된 권한을 부여합니다.

   ```
   postgres=> GRANT lab_tech TO lab_user1;
   GRANT ROLE
   postgres=> GRANT lab_tech TO lab_user2;
   GRANT ROLE
   ```

이 시점에서 `lab_user1`과 `lab_user2`는 `lab_db` 데이터베이스에 연결할 수 있습니다. 이 예제에서는 여러 데이터베이스 인스턴스와 다양한 스키마 생성, 제한된 권한 부여를 포함할 수 있는 엔터프라이즈 사용에 대한 모범 사례를 따르지 않습니다. 전체 정보 및 추가 시나리오를 알아보려면 [PostgreSQL 사용자 및 역할 관리](https://aws.amazon.com/blogs//database/managing-postgresql-users-and-roles/)를 참조하세요.

PostgreSQL 데이터베이스의 권한에 대한 자세한 내용은 PostgreSQL 설명서에서 [GRANT](https://www.postgresql.org/docs/current/static/sql-grant.html) 명령을 참조하세요.

# 사용자 암호 관리 위임 및 제어
<a name="Appendix.PostgreSQL.CommonDBATasks.RestrictPasswordMgmt"></a>

DBA로서 사용자 암호 관리를 위임할 수 있습니다. 또는 데이터베이스 사용자가 암호를 변경하거나 암호 사용 주기와 같은 암호 제약 조건을 재구성하지 못하도록 할 수 있습니다. 선택한 데이터베이스 사용자만 암호 설정을 변경할 수 있도록 하려면 제한된 암호 관리 기능을 켜면 됩니다. 이 기능을 활성화하면 `rds_password` 역할이 부여된 데이터베이스 사용자만 암호를 관리할 수 있습니다.

**참고**  
제한된 암호 관리를 사용하려면 RDS for PostgreSQL DB 인스턴스가 PostgreSQL 10.6 이상을 실행해야 합니다. 

기본적으로 이 기능은 다음과 같이 `off`입니다.

```
postgres=> SHOW rds.restrict_password_commands;
  rds.restrict_password_commands
--------------------------------
 off
(1 row)
```

이 기능을 켜려면 사용자 정의 파라미터 그룹을 사용하고 `rds.restrict_password_commands`에 대한 설정을 1로 변경합니다. RDS for PostgreSQL DB 인스턴스를 재부팅해야 설정이 적용됩니다.

이 기능을 활성화하면 다음 SQL 명령에 대한 `rds_password` 권한이 필요합니다.

```
CREATE ROLE myrole WITH PASSWORD 'mypassword';
CREATE ROLE myrole WITH PASSWORD 'mypassword' VALID UNTIL '2023-01-01';
ALTER ROLE myrole WITH PASSWORD 'mypassword' VALID UNTIL '2023-01-01';
ALTER ROLE myrole WITH PASSWORD 'mypassword';
ALTER ROLE myrole VALID UNTIL '2023-01-01';
ALTER ROLE myrole RENAME TO myrole2;
```

암호에서 MD5 해시 알고리즘을 사용하는 경우에도 역할 이름 변경(`ALTER ROLE myrole RENAME TO newname`)이 제한됩니다.

이 기능이 활성화된 상태에서 `rds_password` 역할 권한 없이 이러한 SQL 명령을 시도하면 다음 오류가 발생합니다.

```
ERROR: must be a member of rds_password to alter passwords
```

암호 관리에만 사용하는 몇 가지 역할에만 `rds_password` 권한을 부여하는 것이 좋습니다. `rds_superuser` 권한이 없는 데이터베이스 사용자에게 `rds_password` 권한을 부여할 경우 `CREATEROLE` 속성도 부여해야 합니다.

만료 및 클라이언트 측에 필요한 복잡성 등의 암호 요구 사항을 확인해야 합니다. 암호 관련 변경 사항에 대해 자체 클라이언트 측 유틸리티를 사용하는 경우 유틸리티가 `rds_password`의 멤버여야 하며 `CREATE ROLE` 권한을 가져야 합니다.

# SCRAM for PostgreSQL 암호 암호화 사용
<a name="PostgreSQL_Password_Encryption_configuration"></a>

*Salted Challenge Response Authentication Mechanism(SCRAM)*은 암호를 암호화하는 데 사용하는 PostgreSQL의 기본 메시지 다이제스트(MD5) 알고리즘을 대체합니다. SCRAM 인증 메커니즘은 MD5보다 더 안전한 것으로 간주됩니다. 이러한 2가지 암호 보호 방법에 대한 자세한 내용은 PostgreSQL 설명서의 [암호 인증](https://www.postgresql.org/docs/14/auth-password.html)을 참조하세요.

MD5가 아닌 SCRAM을 의 암호 암호화 체계로 사용하는 것이 좋습니다. RDS for PostgreSQL DB 인스턴스  이는 암호 인증 및 암호화에 scram-sha-256 알고리즘을 사용하는 암호화 챌린지-응답 메커니즘입니다.

SCRAM을 지원하려면 클라이언트 애플리케이션의 라이브러리를 업데이트해야 할 수 있습니다. 예를 들어, 42.2.0 이전의 JDBC 버전은 SCRAM을 지원하지 않습니다. 자세한 내용은 PostgreSQL JDBC 드라이버 설명서의 [PostgreSQL JDBC 드라이버](https://jdbc.postgresql.org/changelogs/2018-01-17-42.2.0-release/)를 참조하세요. 기타 PostgreSQL 드라이버 및 SCRAM 지원 목록은 PostgreSQL 설명서의 [드라이버 목록](https://wiki.postgresql.org/wiki/List_of_drivers)을 참조하세요.

RDS for PostgreSQL 버전 13.1 이상은 scram-sha-256을 지원합니다. 또한 다음 절차에 설명된 대로 이러한 버전을 사용하여 DB 인스턴스를 SCRAM이 필요하도록 구성할 수 있습니다.

## SCRAM이 필요하도록 RDS for PostgreSQL DB 인스턴스 설정
<a name="PostgreSQL_Password_Encryption_configuration.preliminary"></a>

 RDS for PostgreSQL DB 인스턴스가 scram-sha-256 알고리즘을 사용하는 암호만 수락하도록 요구할 수 있습니다.

**중요**  
PostgreSQL 데이터베이스를 사용하는 기존 RDS 프록시의 경우, `SCRAM`만 사용하도록 데이터베이스 인증을 수정하면 최대 60초 동안 프록시를 사용할 수 없게 됩니다. 문제를 방지하려면 다음 중 하나를 수행합니다.  
데이터베이스에서 `SCRAM` 및 `MD5` 인증이 모두 허용되는지 확인합니다.
`SCRAM` 인증만 사용하려면 새 프록시를 생성하고, 애플리케이션 트래픽을 새 프록시로 마이그레이션한 다음 이전에 데이터베이스와 연결된 프록시를 삭제합니다.

시스템을 변경하기 전에 다음과 같이 전체 프로세스를 이해해야 합니다.
+ 모든 데이터베이스 사용자에 대한 전체 역할 및 암호 암호화에 대한 정보를 가져옵니다.
+ 암호 암호화를 제어하는 파라미터에 대해 RDS for PostgreSQL DB 인스턴스의 파라미터 설정을 다시 확인합니다.
+  RDS for PostgreSQL DB 인스턴스에서 기본 파라미터 그룹을 사용한다면 필요한 경우 파라미터를 수정할 수 있도록 사용자 지정 DB 파라미터 그룹을 생성하고, 이를 RDS for PostgreSQL DB 인스턴스에 적용해야 합니다. RDS for PostgreSQL DB 인스턴스에서 사용자 지정 파라미터 그룹을 사용하는 경우 필요에 따라 과정 후반부에서 필요한 파라미터를 수정할 수 있습니다.
+ `password_encryption` 파라미터를 `scram-sha-256`으로 변경합니다.
+ 모든 데이터베이스 사용자에게 암호를 업데이트해야 함을 알립니다. `postgres` 계정에도 동일한 작업을 수행합니다. 새 암호는 scram-sha-256 알고리즘을 통해 암호화되어 저장됩니다.
+ 모든 암호가 암호화 유형으로 암호화되었는지 확인합니다.
+ 모든 암호가 scram-sha-256을 사용하는 경우 `rds.accepted_password_auth_method` 파라미터를 `md5+scram`에서 `scram-sha-256`으로 변경할 수 있습니다.

**주의**  
`rds.accepted_password_auth_method`를 scram-sha-256으로만 변경하면 `md5`로 암호화된 암호가 있는 사용자(역할)는 연결할 수 없습니다.

### RDS for PostgreSQL DB 인스턴스에서 SCRAM을 사용하도록 준비
<a name="PostgreSQL_Password_Encryption_configuration.getting-ready"></a>

 RDS for PostgreSQL DB 인스턴스를 변경하기에 모든 기존 데이터베이스 사용자 계정을 확인해야 합니다. 또한 암호에 사용되는 암호화 유형도 확인하세요. `rds_tools` 확장을 사용하여 이러한 작업을 수행할 수 있습니다. `rds_tools`를 지원하는 PostgreSQL 버전을 확인하려면 [Amazon RDS for PostgreSQL의 확장 버전](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html)을 참조하세요.

**데이터베이스 사용자(역할) 및 암호 암호화 방법 목록을 가져오려면**

1. 다음과 같이 `psql`을 사용하여 RDS for PostgreSQL DB 인스턴스에 연결합니다.

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

1. `rds_tools` 확장을 설치합니다.

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

1. 역할 및 암호화 목록을 가져옵니다.

   ```
   postgres=> SELECT * FROM 
         rds_tools.role_password_encryption_type();
   ```

   출력은 다음과 비슷합니다.

   ```
          rolname        | encryption_type
   ----------------------+-----------------
    pg_monitor           |
    pg_read_all_settings |
    pg_read_all_stats    |
    pg_stat_scan_tables  |
    pg_signal_backend    |
    lab_tester           | md5
    user_465             | md5
    postgres             | md5
   (8 rows)
   ```

### 사용자 지정 DB 파라미터 그룹 생성
<a name="PostgreSQL_Password_Encryption_configuration.custom-parameter-group"></a>

**참고**  
 RDS for PostgreSQL DB 인스턴스에서 이미 사용자 지정 파라미터 그룹을 사용하는 경우 새로 만들 필요가 없습니다.

Amazon RDS 파라미터 그룹에 대한 개요는 [RDS for PostgreSQL DB 인스턴스에 파라미터로 작업](Appendix.PostgreSQL.CommonDBATasks.Parameters.md) 섹션을 참조하세요.

암호에 사용되는 암호 암호화 유형은 하나의 파라미터 `password_encryption`으로 설정됩니다. RDS for PostgreSQL DB 인스턴스에서 허용하는 암호화는 다른 파라미터인 `rds.accepted_password_auth_method`로 설정됩니다. 이러한 값 중 하나를 기본값에서 변경하려면 사용자 지정 DB 파라미터 그룹을 생성하여 인스턴스에 적용해야 합니다.

AWS Management Console 또는 RDS API를 사용하여 사용자 지정 DB 파라미터 그룹을 생성할 수도 있습니다. 자세한 내용은 단원을 참조하세요.

DB 파라미터 그룹을 DB 인스턴스에 연결합니다.

**사용자 지정 DB 파라미터 그룹을 생성하려면**

1. `[create-db-parameter-group](https://docs.aws.amazon.com/cli/latest/reference/rds/create-db-parameter-group.html) ` CLI 명령을 사용하여 사용자 지정 DB 파라미터 그룹을 생성합니다. 이 예에서는 `postgres13`을 사용자 지정 파라미터 그룹의 소스로 사용합니다.

   대상 LinuxmacOS, 또는Unix:

   ```
   aws rds create-db-parameter-group --db-parameter-group-name 'docs-lab-scram-passwords' \
     --db-parameter-group-family postgres13  --description 'Custom parameter group for SCRAM'
   ```

   Windows의 경우:

   ```
   aws rds create-db-parameter-group --db-parameter-group-name "docs-lab-scram-passwords" ^
     --db-parameter-group-family postgres13  --description "Custom DB parameter group for SCRAM"
   ```

1. `[modify-db-instance](https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-instance.html)` CLI 명령을 사용하여 다음과 같이 사용자 지정 파라미터 그룹을 RDS for PostgreSQL DB 클러스터에 적용합니다.

   대상 LinuxmacOS, 또는Unix:

   ```
   aws rds modify-db-instance --db-instance-identifier 'your-instance-name' \
           --db-parameter-group-name "docs-lab-scram-passwords
   ```

   Windows의 경우:

   ```
   aws rds modify-db-instance --db-instance-identifier "your-instance-name" ^
           --db-parameter-group-name "docs-lab-scram-passwords
   ```

   사용자 지정 DB 파라미터 그룹이 포함된 RDS for PostgreSQL DB 인스턴스를 다시 동기화하려면 클러스터의 프라이머리 및 기타 모든 인스턴스를 재부팅합니다. 사용자에게 미치는 영향을 최소화하기 위해 정기 유지 관리 기간 동안 진행되도록 예약합니다.

### SCRAM을 사용하도록 암호 암호화 구성
<a name="PostgreSQL_Password_Encryption_configuration.configure-password-encryption"></a>

 RDS for PostgreSQL DB 인스턴스에서 사용하는 암호 암호화 메커니즘은 DB 파라미터 그룹에 `password_encryption` 파라미터로 설정되어 있습니다. 허용되는 값은 설정하지 않거나 `md5` 또는 `scram-sha-256`입니다. 기본값은 다음과 같이 RDS for PostgreSQL 버전에 따라 달라집니다.
+ RDS for PostgreSQL 14 이상 – 기본값은 `scram-sha-256`입니다.
+ RDS for PostgreSQL 13 – 기본값은 `md5`입니다.

사용자 지정 DB 파라미터 그룹이 RDS for PostgreSQL DB 인스턴스에 연결되어 있으면 암호 암호화 파라미터 값을 변경할 수 있습니다.

![\[RDS 콘솔에 RDS for PostgreSQL의 password_encryption 파라미터에 대한 기본값이 표시됩니다.\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/images/rpg-pwd-encryption-md5-scram-1.png)


**암호의 암호화 설정을 scram-sha-256으로 변경하려면**
+ 다음과 같이 암호 암호화 값을 scram-sha-256으로 변경합니다. 파라미터가 동적이기 때문에 변경 사항을 즉시 적용할 수 있으므로 변경 사항을 적용하려고 재시작하지 않아도 됩니다.

  대상 LinuxmacOS, 또는Unix:

  ```
  aws rds modify-db-parameter-group --db-parameter-group-name \
    'docs-lab-scram-passwords' --parameters 'ParameterName=password_encryption,ParameterValue=scram-sha-256,ApplyMethod=immediate'
  ```

  Windows의 경우:

  ```
  aws rds modify-db-parameter-group --db-parameter-group-name ^
    "docs-lab-scram-passwords" --parameters "ParameterName=password_encryption,ParameterValue=scram-sha-256,ApplyMethod=immediate"
  ```

### 사용자 역할의 암호를 SCRAM으로 마이그레이션
<a name="PostgreSQL_Password_Encryption_configuration.migrating-users"></a>

다음에 설명된 대로 사용자 역할에 대한 암호를 SCRAM으로 마이그레이션할 수 있습니다.

**MD5에서 SCRAM으로 데이터베이스 사용자(역할) 암호를 마이그레이션하려면**

1. 다음과 같이 관리자 사용자로 로그인(기본 사용자 이름 `postgres`)합니다.

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

1. 다음 명령을 사용하여 RDS for PostgreSQL DB 인스턴스의 `password_encryption` 파라미터 설정을 확인합니다.

   ```
   postgres=> SHOW password_encryption;
    password_encryption
   ---------------------
    md5
    (1 row)
   ```

1. 이 파라미터의 값을 scram-sha-256으로 변경합니다. 자세한 내용은 [SCRAM을 사용하도록 암호 암호화 구성](#PostgreSQL_Password_Encryption_configuration.configure-password-encryption) 섹션을 참조하세요.

1.  다음과 같이 `scram-sha-256`으로 설정되어 있는지 값을 다시 확인합니다.

   ```
   postgres=> SHOW password_encryption;
    password_encryption
   ---------------------
    scram-sha-256
    (1 row)
   ```

1. 모든 데이터베이스 사용자에게 암호 변경을 알립니다. 계정 `postgres`(`rds_superuser` 권한을 지닌 데이터베이스 사용자)의 자체 암호도 변경해야 합니다.

   ```
   labdb=> ALTER ROLE postgres WITH LOGIN PASSWORD 'change_me';
   ALTER ROLE
   ```

1. 에 모든 데이터베이스에 대해 프로세스를 반복합니다. RDS for PostgreSQL DB 인스턴스  

### SCRAM이 필요하도록 파라미터 변경
<a name="PostgreSQL_Password_Encryption_configuration.require-scram"></a>

과정의 마지막 단계입니다. 다음 절차에서 변경한 후에도 암호에 `md5` 암호화를 계속 사용하는 모든 사용자 계정(역할)은 에 로그인할 수 없습니다. RDS for PostgreSQL DB 인스턴스  

`rds.accepted_password_auth_method`는 로그인하는 동안 RDS for PostgreSQL DB 인스턴스가 사용자 암호에 대해 허용하는 암호화 방법을 지정합니다. 기본값은 `md5+scram`이므로, 두 방법 중 하나를 사용할 수 있습니다. 다음 이미지에서는 이 파라미터에 대한 기본 설정을 찾을 수 있습니다.

![\[RDS 콘솔에서 rds.accepted_password_auth_method 파라미터에 대한 기본 값과 허용된 값을 표시합니다.\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/images/pwd-encryption-md5-scram-2.png)


이 파라미터에 허용되는 값은 `md5+scram` 또는 `scram`입니다. 이 파라미터 값을 `scram`으로 변경하여 필수로 설정합니다.

**암호에 SCRAM 인증을 요구하도록 파라미터 값을 변경하려면**

1.  RDS for PostgreSQL DB 인스턴스의 모든 데이터베이스에 대한 전체 데이터베이스 사용자 암호가 암호 암호화에 `scram-sha-256`을 사용하는지 확인합니다. 이렇게 하려면 다음과 같이 역할(사용자) 및 암호화 유형에 대해 `rds_tools`를 쿼리합니다.

   ```
   postgres=> SELECT * FROM rds_tools.role_password_encryption_type();
     rolname        | encryption_type
     ----------------------+-----------------
     pg_monitor           |
     pg_read_all_settings |
     pg_read_all_stats    |
     pg_stat_scan_tables  |
     pg_signal_backend    |
     lab_tester           | scram-sha-256
     user_465             | scram-sha-256
     postgres             | scram-sha-256
     ( rows)
   ```

1. 의 모든 DB 인스턴스에서 쿼리를 반복합니다. RDS for PostgreSQL DB 인스턴스  

   모든 암호가 scram-sha-256을 사용하는 경우 그대로 진행하면 됩니다.

1. 다음과 같이 허용된 암호 인증의 값을 scram-sha-256으로 변경합니다.

   대상 LinuxmacOS, 또는Unix:

   ```
   aws rds modify-db-parameter-group --db-parameter-group-name 'docs-lab-scram-passwords' \
     --parameters 'ParameterName=rds.accepted_password_auth_method,ParameterValue=scram,ApplyMethod=immediate'
   ```

   Windows의 경우:

   ```
   aws rds modify-db-parameter-group --db-parameter-group-name "docs-lab-scram-passwords" ^
     --parameters "ParameterName=rds.accepted_password_auth_method,ParameterValue=scram,ApplyMethod=immediate"
   ```

# PostgreSQL에서 연결 중단 처리
<a name="Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling"></a>

클라이언트 애플리케이션이 중단되거나 비정상적으로 종료된 경우에도 서버에서 데이터베이스 세션이 활성 상태로 유지될 때 연결 중단이 발생합니다. 이 상황은 일반적으로 클라이언트가 데이터베이스 연결을 제대로 닫거나 진행 중인 요청을 취소하지 않고 충돌을 처리하거나 예기치 않게 종료할 때 발생합니다.

PostgreSQL은 서버 프로세스가 유휴 상태이거나 클라이언트로 데이터를 전송하려고 할 때 연결 중단을 효율적으로 식별하고 정리합니다. 그러나 유휴 상태이거나 클라이언트 입력을 기다리거나 쿼리를 적극적으로 실행하는 세션의 경우 감지가 어렵습니다. 이러한 시나리오를 처리하기 위해 PostgreSQL은 `tcp_keepalives_*`, `tcp_user_timeout` 및 `client_connection_check_interval` 파라미터를 제공합니다.

**Topics**
+ [TCP 킵얼라이브 이해](#Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling.Understanding)
+ [RDS for PostgreSQL의 주요 TCP 킵얼라이브 파라미터](#Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling.Parameters)
+ [TCP 킵얼라이브 설정 사용 사례](#Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling.UseCases)
+ [모범 사례](#Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling.BestPractices)

## TCP 킵얼라이브 이해
<a name="Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling.Understanding"></a>

TCP 킵얼라이브는 연결 무결성을 유지하고 확인하는 데 도움이 되는 프로토콜 수준 메커니즘입니다. 각 TCP 연결은 킵얼라이브 동작을 제어하는 커널 수준 설정을 유지 관리합니다. 킵얼라이브 타이머가 만료되면 시스템은 다음을 수행합니다.
+ 데이터 및 ACK 플래그 세트가 없는 프로브 패킷을 전송합니다.
+ TCP/IP 사양에 따라 원격 엔드포인트에서 응답을 예상합니다.
+ 응답 또는 응답 없음을 기반으로 연결 상태를 관리합니다.

## RDS for PostgreSQL의 주요 TCP 킵얼라이브 파라미터
<a name="Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling.Parameters"></a>


| 파라미터 | 설명 | 기본값 | 
| --- |--- |--- |
| tcp\$1keepalives\$1idle | Specifies number of seconds of inactivity before sending keepalive message. | 300 | 
| tcp\$1keepalives\$1interval | Specifies number of seconds between retransmissions of unacknowledged keepalive messages. | 30 | 
| tcp\$1keepalives\$1count | Maximum lost keepalive messages before declaring connection dead | 2 | 
| tcp\$1user\$1timeout | Specifies how long (in Milliseconds) unacknowledged data can remain before forcibly closing the connection. | 0 | 
| client\$1connection\$1check\$1interval | Sets the interval (in Milliseconds) for checking client connection status during long-running queries. This ensures quicker detection of closed connections. | 0 | 

## TCP 킵얼라이브 설정 사용 사례
<a name="Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling.UseCases"></a>

### 유휴 세션 연결 유지
<a name="Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling.UseCases.KeepingAlive"></a>

활동이 없어 방화벽 또는 라우터에 의해 유휴 연결이 종료되지 않도록 하는 방법:
+ 정기적으로 킵얼라이브 패킷을 전송하도록 `tcp_keepalives_idle`을 구성합니다.

### 연결 중단 감지
<a name="Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling.UseCases.DetectingDead"></a>

연결 중단을 즉시 감지하는 방법:
+ `tcp_keepalives_idle`, `tcp_keepalives_interval` 및 `tcp_keepalives_count`를 조정합니다. 예를 들어 Aurora PostgreSQL 기본값을 사용하면 연결 중단을 감지하는 데 약 1분(프로브 2개 × 30초)이 걸립니다. 이러한 값을 낮추면 감지 속도가 빨라질 수 있습니다.
+ `tcp_user_timeout`을 사용하여 확인의 최대 대기 시간을 지정합니다.

TCP 킵얼라이브 설정은 커널이 연결 중단을 감지하는 데 도움이 되지만 소켓을 사용할 때까지 PostgreSQL이 작동하지 않을 수 있습니다. 세션이 긴 쿼리를 실행하는 경우 쿼리가 완료된 후에야 연결 중단이 감지될 수 있습니다. PostgreSQL 14 이상 버전에서는 `client_connection_check_interval`이 쿼리 실행 중에 소켓을 주기적으로 폴링하여 연결 중단 감지를 가속화할 수 있습니다.

## 모범 사례
<a name="Appendix.PostgreSQL.CommonDBATasks.DeadConnectionHandling.BestPractices"></a>
+ **적절한 킵얼라이브 간격 설정:** `tcp_user_timeout`, `tcp_keepalives_idle`, `tcp_keepalives_count` 및 `tcp_keepalives_interval`을 조정하여 감지 속도와 리소스 사용의 균형을 맞춥니다.
+ **환경에 최적화:** 네트워크 동작, 방화벽 정책 및 세션 요구 사항에 맞게 설정을 조정합니다.
+ **PostgreSQL 기능 활용:** 효율적인 연결 확인을 위해 PostgreSQL 14 이상 버전에서 `client_connection_check_interval`을 사용합니다.

# 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`를 수동으로 시작하여 트랜잭션 실패를 방지해야 합니다.

# Amazon RDS for PostgreSQL에서 다수의 객체 관리
<a name="PostgreSQL.HighObjectCount"></a>

PostgreSQL 제한은 이론적이지만 데이터베이스의 객체 수가 매우 많으면 다양한 작업에서 성능에 상당한 영향을 미칠 수 있습니다. 이 설명서에서는 총 객체 수가 많을 때 여러 가지 영향을 미칠 수 있는 몇 가지 일반적인 객체 유형을 다룹니다.

다음 표에는 객체 유형과 그 잠재적 영향에 대한 요약이 있습니다.


**객체 유형 및 잠재적 영향**  

| 객체 유형 | AUTOVACUUM | 논리적 복제 | 메이저 버전 업그레이드 | pg\$1dump/pg\$1restore | 일반 성능 | 인스턴스 재시작 | 
| --- | --- | --- | --- | --- | --- | --- | 
| [관계](#PostgreSQL.HighObjectCount.Relations) | x |  | x | x | x |  | 
| [임시 테이블](#PostgreSQL.HighObjectCount.TempTables). | x |  |  |  | x |  | 
| [로깅되지 않은 테이블](#PostgreSQL.HighObjectCount.UnloggedTables) |  | x |  |  |  | x | 
| [파티션](#PostgreSQL.HighObjectCount.Partitions) |  |  |  |  | x |  | 
| [임시 파일](#PostgreSQL.HighObjectCount.TempFiles) |  |  |  |  | x |  | 
| [시퀀스](#PostgreSQL.HighObjectCount.Sequences) |  | x |  |  |  |  | 
| [대형 객체](#PostgreSQL.HighObjectCount.LargeObjects) |  | x | x |  |  |  | 

## 관계
<a name="PostgreSQL.HighObjectCount.Relations"></a>

PostgreSQL 데이터베이스의 테이블 수에는 구체적인 하드 제한이 없습니다. 이론적인 한도는 매우 높지만 데이터베이스 설계 중에 염두에 두어야 할 다른 실제 한도가 있습니다.

**영향: Autovacuum이 뒤처짐**  
Autovacuum이 작업량에 비해 작업자가 부족하여 트랜잭션 ID 증가 또는 테이블 팽창을 따라잡는 데 어려움을 겪을 수 있습니다.  
**권장 작업:** Autovacuum을 조정하여 지정된 수의 테이블과 지정된 워크로드를 제대로 따라잡기 위한 몇 가지 요소가 있습니다. 적절한 Autovacuum 설정을 결정하는 방법에 대한 제안은 [PostgreSQL Autovacuum 작업 모범 사례](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Autovacuum.html)를 참조하세요. [postgres\$1get\$1av\$1diag 유틸리티](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Functions.html)를 사용하여 트랜잭션 ID 증가 문제를 모니터링합니다.

**영향: 메이저 버전 업그레이드/pg\$1dump 및 복원**  
Amazon RDS는 pg\$1upgrade 실행 중에 "--link" 옵션을 사용하여 데이터 파일을 복사할 필요가 없습니다. 스키마 메타데이터는 여전히 데이터베이스의 새 버전으로 복원해야 합니다. 병렬 pg\$1restore를 사용하더라도 관계의 수가 많으면 가동 중지 시간이 늘어납니다.

**영향: 일반 성능 저하**  
카탈로그 크기로 인해 일반적인 성능이 저하됩니다. 각 테이블과 연결된 열은 일반 데이터베이스 작업에 자주 사용되는 `pg_attribute`, `pg_class` 및 `pg_depend` 테이블에 추가됩니다. 특정 대기 이벤트는 표시되지 않지만 공유 버퍼 효율성은 영향을 받습니다.  
**권장 작업:** 이러한 특정 테이블에 대한 테이블 팽창을 정기적으로 확인하고 가끔 이러한 특정 테이블에 대해 `VACUUM FULL`을 수행합니다. 카탈로그 테이블에서 `VACUUM FULL`에는 `ACCESS EXCLUSIVE` 잠금이 필요합니다. 즉, 작업이 완료될 때까지 다른 쿼리는 액세스할 수 없습니다.

**영향: 파일 설명자 소진**  
오류: "파일 설명자 부족: 시스템에 열려 있는 파일이 너무 많습니다. 릴리스 및 재시도하세요." PostgreSQL 파라미터 `max_files_per_process`는 각 프로세스가 열 수 있는 파일 수를 결정합니다. 많은 수의 테이블을 조인하는 연결 수가 많은 경우 이 제한에 도달할 수 있습니다.  
**권장 조치:**  
+ 파라미터 `max_files_per_process`의 값을 낮추면 이 오류를 완화하는 데 도움이 될 수 있습니다. 각 프로세스 및 하위 프로세스(예: 병렬 쿼리)는 이 수의 파일을 열 수 있으며 쿼리가 여러 테이블을 조인하는 경우 이 제한이 소진될 수 있습니다.
+ 전체 연결 수를 줄이고 [Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html)와 같은 연결 풀러 또는 PgBouncer와 같은 기타 솔루션을 사용합니다. 자세히 알아보려면 [PgBouncer](https://www.pgbouncer.org/) 웹 사이트를 참조하세요.

**영향: Inode 소진**  
“디바이스에 남은 공간 없음” 오류가 표시됩니다. 스토리지 여유 공간이 많은데 이러한 현상이 관찰되었다면 inode가 부족해지고 있기 때문입니다. [Amazon RDS Enhanced Monitoring](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Monitoring.OS.html)은 사용 중인 inode에 대한 가시성과 호스트에 사용할 수 있는 최대 수를 제공합니다.

**대략적인 임계값:** [수백만](#PostgreSQL.HighObjectCount.Note)

## 임시 테이블
<a name="PostgreSQL.HighObjectCount.TempTables"></a>

임시 테이블 사용은 테스트 데이터 또는 중간 결과에 유용하며 많은 데이터베이스 엔진에서 볼 수 있는 일반적인 패턴입니다. 일부 위험을 방지하려면 PostgreSQL에서 과도한 사용의 영향을 이해해야 합니다. 각 임시 테이블 생성 및 삭제는 시스템 카탈로그 테이블에 행을 추가하며, 테이블이 팽창하면 일반적인 성능 문제가 발생합니다.

**영향: Autovacuum이 뒤처짐**  
임시 테이블은 autovacuum에 의해 vacuum되지 않지만, 존재하는 동안 트랜잭션 ID를 유지하고 제거하지 않으면 랩어라운드로 이어질 수 있습니다.  
**권장 작업:** 임시 테이블은 테이블을 생성한 세션 기간 동안 유지되거나 수동으로 삭제할 수 있습니다. 임시 테이블을 사용하여 장기 실행 트랜잭션을 방지하는 모범 사례는 이러한 테이블이 최대 사용 트랜잭션 ID 증가에 기여하지 못하게 합니다.

**영향: 일반 성능 저하**  
카탈로그 크기로 인해 일반적인 성능이 저하됩니다. 세션이 임시 테이블을 지속적으로 생성하고 삭제할 때, 일반 데이터베이스 작업에 자주 사용되는 `pg_attribute`, `pg_class` 및 `pg_depend` 테이블에 추가됩니다. 특정 대기 이벤트는 표시되지 않지만 공유 버퍼 효율성은 영향을 받습니다.  
**권장 조치:**  
+ 이러한 특정 테이블에 대한 테이블 팽창을 정기적으로 확인하고 가끔 이러한 특정 테이블에 대해 `VACUUM FULL`을 수행합니다. 카탈로그 테이블에서 `VACUUM FULL`에는 `ACCESS EXCLUSIVE` 잠금이 필요합니다. 즉, 작업이 완료될 때까지 다른 쿼리는 액세스할 수 없습니다.
+ 임시 테이블이 많이 사용되는 경우 메이저 버전 업그레이드 전에 가동 중지 시간을 줄이기 위해 이러한 특정 카탈로그 테이블의 `VACUUM FULL`을 사용하는 것이 좋습니다.

**일반 모범 사례:**
+ 일반적인 테이블 표현식을 사용해 중간 결과를 생성하여 임시 테이블 사용을 줄입니다. 이렇게 하면 필요한 쿼리를 복잡해질 수 있지만 위에 나열된 영향이 제거됩니다.
+ 삭제/생성 단계를 수행하는 대신 `TRUNCATE` 명령을 사용하여 콘텐츠를 지워 임시 테이블을 재사용합니다. 이렇게 하면 임시 테이블로 인한 트랜잭션 ID 증가 문제도 제거됩니다.

**대략적인 임계값:** [수만](#PostgreSQL.HighObjectCount.Note)

## 로깅되지 않은 테이블
<a name="PostgreSQL.HighObjectCount.UnloggedTables"></a>

로깅되지 않은 테이블은 WAL 정보를 생성하지 않으므로 성능 향상을 제공할 수 있습니다. 데이터베이스 충돌 복구 중에는 잘릴 것이므로 내구성을 제공하지 않으므로 신중하게 사용해야 합니다. PostgreSQL에서는 로깅되지 않은 각 테이블이 순차적으로 잘리기 때문에 작업에 비용이 많이 듭니다. 이 작업은 로깅되지 않은 테이블 수가 적은 경우에는 속도가 빠르지만, 수천 개 단위로 계산되면 시작 중에 눈에 띄는 지연을 추가되기 시작할 수 있습니다.

**영향: 논리적 복제**  
[블루/그린 배포](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/blue-green-deployments.html)를 포함한 논리적 복제는 WAL을 사용하여 변경 사항을 캡처하고 전송하기 때문에 로깅되지 않은 테이블은 일반적으로 논리적 복제에 포함되지 않습니다. 

  


**영향: 복구 중 가동 중지 시간 연장**  
장애 조치를 사용한 다중 AZ 재부팅, Amazon RDS 특정 시점 복구, Amazon RDS 메이저 버전 업그레이드와 같은 데이터베이스 충돌 복구와 관련된 데이터베이스 상태 중에는 로깅되지 않은 테이블을 잘라내는 직렬화된 작업이 발생합니다. 이로 인해 가동 중지 시간이 예상보다 훨씬 길어질 수 있습니다.  
**권장 조치:**  
+ 데이터베이스 충돌 복구 작업 중에 손실될 수 있는 데이터로만 로깅되지 않은 테이블의 사용을 최소화합니다.
+ 로깅되지 않은 테이블을 현재 직렬 잘라내기 동작으로 사용하는 것을 최소화하면 데이터베이스 시작에 상당한 시간이 걸릴 수 있습니다.

**일반 모범 사례:**
+ 로깅되지 않은 테이블은 충돌에 안전하지 않습니다. 충돌 복구를 수반하는 특정 시점으로 복구를 시작하는 것은 각 테이블을 잘라내는 직렬 프로세스이므로 PostgreSQL에서 상당한 시간이 걸립니다.

**대략적인 임계값:** [수천](#PostgreSQL.HighObjectCount.Note)

## 파티션
<a name="PostgreSQL.HighObjectCount.Partitions"></a>

파티셔닝은 쿼리 성능을 높이고 데이터의 논리적 구성을 제공할 수 있습니다. 이상적인 시나리오에서는 파티셔닝이 구성되어 쿼리 계획 및 실행 중에 파티션 정리를 사용할 수 있습니다. 파티션을 너무 많이 사용하면 쿼리 성능 및 데이터베이스 유지 관리에 부정적인 영향을 미칠 수 있습니다. 잘못된 설계로 인해 쿼리 계획 및 실행 성능이 부정적인 영향을 받을 수 있으므로 테이블을 분할하는 방법을 신중하게 선택해야 합니다. 파티셔닝에 대한 자세한 내용은 [PostgreSQL 설명서](https://www.postgresql.org/docs/current/ddl-partitioning.html)를 참조하세요.

**영향: 일반 성능 저하**  
간혹 시간 계획 오버헤드가 증가하고 쿼리에 대한 계획이 더 복잡해져 튜닝 기회를 식별하기가 어려워집니다. PostgreSQL 18 이전 버전의 경우 워크로드가 많은 여러 파티션에 `LWLock:LockManager` 대기가 발생할 수 있습니다.  
**권장 작업:** 성능 있는 쿼리 실행을 제공하는 동시에 데이터 구성을 모두 완료할 수 있는 최소 파티션 수를 결정합니다.

**영향: 유지 관리 복잡성**  
파티션 수가 매우 많으면 사전 생성 및 제거와 같은 유지 관리 문제가 발생합니다. Autovacuum은 파티션을 일반적인 관계로 취급하며, 정기적인 정리를 수행해야 하므로 작업을 완료하는 데 충분한 작업자가 필요합니다.  
**권장 조치:**  
+ 새 파티션이 필요하고(예: 월별 기반 파티션) 이전 파티션이 롤오프될 때 워크로드가 차단되지 않도록 파티션을 미리 생성해야 합니다.
+ 모든 파티션의 일반적인 정리 유지 관리를 수행할 수 있는 Autovacuum 작업자가 충분한지 확인합니다.

**대략적인 임계값:** [수백](#PostgreSQL.HighObjectCount.Note)

## 임시 파일
<a name="PostgreSQL.HighObjectCount.TempFiles"></a>

위에서 언급한 임시 테이블과는 다르게 임시 파일은 복잡한 쿼리가 여러 가지 정렬 또는 해시 연산을 동시에 수행할 때 PostgreSQL에서 생성되며, 각 연산은 인스턴스 메모리를 사용하여 `work_mem` 파라미터에 지정된 값까지 결과를 저장합니다. 인스턴스 메모리가 충분하지 않은 경우 결과를 저장하기 위한 임시 파일이 생성됩니다. 임시 파일에 대한 자세한 내용은 [임시 파일 관리](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/PostgreSQL.ManagingTempFiles.html)를 참조하세요. 워크로드에서 이러한 파일을 다수 생성하면 여러 가지 영향이 있을 수 있습니다.

  


**영향: 파일 설명자 소진**  
오류: "파일 설명자 부족: 시스템에 열려 있는 파일이 너무 많습니다. 릴리스 및 재시도하세요." PostgreSQL 파라미터 `max_files_per_process`는 각 프로세스가 열 수 있는 파일 수를 결정합니다. 많은 수의 테이블을 조인하는 연결 수가 많은 경우 이 제한에 도달할 수 있습니다.  
**권장 조치:**  
+ 파라미터 `max_files_per_process`의 값을 낮추면 이 오류를 완화하는 데 도움이 될 수 있습니다. 각 프로세스 및 하위 프로세스(예: 병렬 쿼리)는 이 수의 파일을 열 수 있으며 쿼리가 여러 테이블을 조인하는 경우 이 제한이 소진될 수 있습니다.
+ 전체 연결 수를 줄이고 [Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html)와 같은 연결 풀러 또는 PgBouncer와 같은 기타 솔루션을 사용합니다. 자세히 알아보려면 [PgBouncer](https://www.pgbouncer.org/) 웹 사이트를 참조하세요.

**영향: Inode 소진**  
“디바이스에 남은 공간 없음” 오류가 표시됩니다. 스토리지 여유 공간이 많은데 이러한 현상이 관찰되었다면 inode가 부족해지고 있기 때문입니다. [Amazon RDS 향상된 모니터링](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Monitoring.OS.html)은 사용 중인 inode에 대한 가시성과 호스트에 사용할 수 있는 최대 수를 제공합니다.

**일반 모범 사례:**
+ [성능 개선 도우미](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_PerfInsights.html)를 사용하여 임시 파일 사용량을 모니터링합니다.
+ 중요한 임시 파일을 생성하는 쿼리를 조정하여 임시 파일의 총 수를 줄일 수 있는지 확인합니다.

**대략적인 임계값:** [수천](#PostgreSQL.HighObjectCount.Note)

## 시퀀스
<a name="PostgreSQL.HighObjectCount.Sequences"></a>

시퀀스는 PostgreSQL에서 열을 자동 증분하는 데 사용되는 기본 객체이며 데이터의 고유성과 키를 제공합니다. 논리적 복제를 제외하고 정상 작업 중에는 결과 없이 개별 테이블에서 사용할 수 있습니다.

PostgreSQL에서 논리적 복제는 현재 시퀀스의 현재 값을 구독자에게 복제하지 않습니다. 자세한 내용은 [PostgreSQL 설명서의 등록 페이지](https://www.postgresql.org/docs/current/logical-replication-restrictions.html)를 참조하세요.

**영향: 전환 시간 연장**  
모든 유형의 구성 변경 또는 업그레이드에 [Amazon RDS 블루/그린 배포](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/blue-green-deployments.html)를 사용하려는 경우 많은 시퀀스가 전환에 미치는 영향을 이해하는 것이 중요합니다. 전환의 마지막 단계 중 하나는 시퀀스의 현재 값을 동기화하며, 수천 개가 있는 경우 전체 전환 시간이 늘어납니다.  
**권장 작업:** 데이터베이스 워크로드에서 테이블당 시퀀스 접근 방식 대신 공유 UUID를 사용할 수 있는 경우, 전환 중에 동기화 단계가 중단됩니다.

**대략적인 임계값:** [수천](#PostgreSQL.HighObjectCount.Note)

## 대형 객체
<a name="PostgreSQL.HighObjectCount.LargeObjects"></a>

큰 객체는 pg\$1largeobject라는 단일 시스템 테이블에 저장됩니다. 또한 각 대형 객체에는 시스템 테이블 pg\$1largeobject\$1metadata에 항목이 있습니다. 이러한 객체는 표준 관계와 크게 다르게 생성, 수정 및 정리됩니다. 대형 객체는 autovacuum에서 처리하지 않으며 vacuumlo라는 별도의 프로세스를 통해 주기적으로 정리해야 합니다. 대형 객체 관리에 대한 예제는 lo 모듈을 사용한 대형 객체 관리를 참조하세요.

**영향: 논리적 복제**  
큰 객체는 현재 논리적 복제 중에 PostgreSQL에 복제되지 않습니다. 자세한 내용은 [PostgreSQL 설명서의 등록 페이지](https://www.postgresql.org/docs/current/logical-replication-restrictions.html)를 참조하세요. [블루/그린](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/blue-green-deployments.html) 구성에서는 블루 환경의 큰 객체가 그린 환경에 복제되지 않습니다.

**영향: 메이저 버전 업그레이드**  
대형 객체가 수백만 개이고 인스턴스가 업그레이드 중에 이를 처리할 수 없는 경우 메모리 부족이 발생하여 업그레이드가 실패할 수 있습니다. PostgreSQL 메이저 버전 업그레이드 프로세스는 크게 두 단계로 구성됩니다. pg\$1dump를 통해 스키마를 덤프하는 단계와 pg\$1restore를 통해 스키마를 복원하는 단계입니다. 데이터베이스에 수백만 개의 대형 객체가 있는 경우 업그레이드 중에 pg\$1dump 및 pg\$1restore를 처리할 수 있도록 인스턴스에 충분한 메모리가 있는지 확인하고 더 큰 인스턴스 유형으로 규모를 조정해야 합니다.

**일반 모범 사례:**
+ vacuumlo 유틸리티를 정기적으로 사용하여 고립된 큰 객체를 제거합니다.
+ 데이터베이스에 대용량 객체를 저장하려면 BYTEA 데이터 유형을 사용하는 것이 좋습니다.

**대략적인 임계값:** [수백만](#PostgreSQL.HighObjectCount.Note)

## 대략적인 임계값
<a name="PostgreSQL.HighObjectCount.Note"></a>

이 주제에 언급된 대략적인 임계값은 특정 리소스의 규모를 추정하는 데만 사용됩니다. 설명된 영향이 발생할 가능성이 더 높은 일반적인 범위를 나타내지만 실제 동작은 구체적인 워크로드, 인스턴스 크기 및 구성에 따라 달라집니다. 이러한 추정치를 초과할 수 있지만 나열된 영향을 방지하기 위해 주의 및 유지 관리를 준수해야 합니다.

# Amazon RDS for PostgreSQL에서 TOAST OID 경합 관리
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID"></a>

TOAST(Oversized-Attribute Storage Technique)는 일반적인 8KB 데이터베이스 블록 크기를 초과하는 큰 데이터 값을 처리하도록 설계된 PostgreSQL 기능입니다. PostgreSQL은 물리적 행이 여러 블록에 걸쳐 있는 것을 허용하지 않습니다. 블록 크기는 행 크기에 대한 상한 역할을 합니다. TOAST는 큰 필드 값을 더 작은 청크로 분할하여 이러한 제한을 극복합니다. 기본 테이블에 연결된 전용 TOAST 테이블에 별도로 저장합니다. 자세한 내용은 [PostgreSQL TOAST 스토리지 메커니즘 및 구현 설명서](https://www.postgresql.org/docs/current/storage-toast.html)를 참조하세요.

**Topics**
+ [TOAST 작업 이해](#Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.HowWorks)
+ [성능 문제 식별](#Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.PerformanceChallenges)
+ [추천](#Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.Recommendations)
+ [모니터링](#Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.Monitoring)

## TOAST 작업 이해
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.HowWorks"></a>

TOAST는 압축을 수행하고 큰 필드 값을 일렬로 저장합니다. TOAST는 TOAST 테이블에 저장된 각 크기 초과 데이터 청크에 고유한 OID(객체 식별자)를 할당합니다. 기본 테이블은 TOAST 테이블의 해당 행을 참조하기 위해 TOAST 값 ID와 관계 ID를 페이지에 저장합니다. 이를 통해 PostgreSQL은 이러한 TOAST 청크를 효율적으로 찾고 관리할 수 있습니다. 그러나 TOAST 테이블이 증가함에 따라, 시스템에서 사용 가능한 OID가 소진되어 성능 저하와 OID 고갈로 인한 잠재적 가동 중지 시간이 발생할 위험이 있습니다.

### TOAST의 객체 식별자
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.ObjectIdentifiers"></a>

객체 식별자(OID)는 PostgreSQL에서 테이블, 인덱스 및 함수와 같은 데이터베이스 객체를 참조하는 데 사용하는 시스템 전체의 고유 식별자입니다. 이러한 식별자는 PostgreSQL의 내부 작업에서 중요한 역할을 하므로 데이터베이스가 객체를 효율적으로 찾고 관리할 수 있습니다.

토스팅에 적합한 데이터 세트가 있는 테이블의 경우 PostgreSQL은 OID를 할당하여 연결된 TOAST 테이블에 저장된 크기 초과 데이터의 각 청크를 고유하게 식별합니다. 시스템은 각 청크를 `chunk_id`와 연결하므로 PostgreSQL이 TOAST 테이블 내에서 이러한 청크를 효율적으로 구성하고 찾을 수 있습니다.

## 성능 문제 식별
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.PerformanceChallenges"></a>

PostgreSQL의 OID 관리는 40억 개의 고유 값을 생성한 후 래핑되도록 글로벌 32비트 카운터를 사용합니다. 데이터베이스 클러스터가 이 카운터를 공유하는 동안 OID 할당에는 TOAST 작업 중 두 단계가 포함됩니다.
+ **할당을 위한 글로벌 카운터** - 글로벌 카운터는 클러스터 전체에 새 OID를 할당합니다.
+ **로컬 충돌 검색** - TOAST 테이블은 새 OID가 해당 특정 테이블에 이미 사용된 기존 OID와 충돌하지 않도록 합니다.

성능 저하는 다음과 같은 경우에 발생할 수 있습니다.
+ TOAST 테이블의 조각화 수준이 높거나 OID 사용량이 밀집되어 OID 할당이 지연됩니다.
+ 시스템은 TOAST를 광범위하게 사용하는 데이터 이탈이 높거나 넓은 테이블이 있는 환경에서 OID를 자주 할당하고 재사용합니다.

자세한 내용은 [PostgreSQL TOAST 테이블 크기 제한 및 OID 할당 설명서](https://wiki.postgresql.org/wiki/TOAST#Total_table_size_limit)를 참조하세요.

글로벌 카운터는 OID를 생성하고 40억 개마다 값을 래핑하므로 시스템은 때때로 이미 사용된 값을 다시 생성합니다. PostgreSQL은 이를 감지하고 다음 OID로 다시 시도합니다. TOAST 테이블에 간격 없이 사용된 OID 값이 매우 오래 실행되는 경우 느린 INSERT가 발생할 수 있습니다. OID 공간이 가득 차면 이러한 문제가 더욱 두드러져 삽입 및 업데이트 속도가 느려집니다.

### 문제 식별
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.IdentifyingProblem"></a>
+ 단순 `INSERT` 문은 일관되지 않고 무작위적인 방식으로 평소보다 훨씬 오래 걸립니다.
+ 지연은 TOAST 작업과 관련된 `INSERT` 및 `UPDATE` 문에만 발생합니다.
+ 시스템이 TOAST 테이블에서 사용 가능한 OID를 찾는 데 어려움을 겪으면 PostgreSQL 로그에 다음 로그 항목이 나타납니다.

  ```
  LOG: still searching for an unused OID in relation "pg_toast_20815"
  DETAIL: OID candidates have been checked 1000000 times, but no unused OID has been found yet.
  ```
+ Performance Insights는 `LWLock:buffer_io` 및 `LWLock:OidGenLock` 대기 이벤트와 관련된 평균 활성 세션(AAS) 수가 많음을 나타냅니다.

  다음 SQL 쿼리를 실행하여 대기 이벤트가 있는 장기 실행 INSERT 트랜잭션을 식별할 수 있습니다.

  ```
  SELECT
      datname AS database_name,
      usename AS database_user,
      pid,
      now() - pg_stat_activity.xact_start AS transaction_duration,
      concat(wait_event_type, ':', wait_event) AS wait_event,
      substr(query, 1, 30) AS TRANSACTION,
      state
  FROM
      pg_stat_activity
  WHERE (now() - pg_stat_activity.xact_start) > INTERVAL '60 seconds'
      AND state IN ('active', 'idle in transaction', 'idle in transaction (aborted)', 'fastpath function call', 'disabled')
      AND pid <> pg_backend_pid()
  AND lower(query) LIKE '%insert%'
  ORDER BY
      transaction_duration DESC;
  ```

  대기 시간이 연장된 INSERT 작업을 표시하는 쿼리 결과의 예:

  ```
   database_name |  database_user  |  pid  | transaction_duration |     wait_event      |          transaction           | state
  ---------------+-----------------+-------+----------------------+---------------------+--------------------------------+--------
   postgres       | db_admin_user| 70965 | 00:10:19.484061      | LWLock:buffer_io    | INSERT INTO "products" (......... | active
   postgres       | db_admin_user| 69878 | 00:06:14.976037      | LWLock:buffer_io    | INSERT INTO "products" (......... | active
   postgres       | db_admin_user| 68937 | 00:05:13.942847      | :                   | INSERT INTO "products" (......... | active
  ```

### 문제 격리
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.IsolatingProblem"></a>
+ **작은 삽입 테스트** - `toast_tuple_target` 임계값보다 작은 레코드를 삽입합니다. TOAST 스토리지 전에 압축이 적용됩니다. 성능 문제 없이 작동하는 경우이 문제는 TOAST 작업과 관련이 있습니다.
+ **새 테이블 테스트** - 구조가 동일한 새 테이블을 생성하고 `toast_tuple_target`보다 큰 레코드를 삽입합니다. 문제 없이 작동하는 경우 문제가 원래 테이블의 OID 할당으로 현지화됩니다.

## 추천
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.Recommendations"></a>

다음 접근 방식은 TOAST OID 경합 문제를 해결하는 데 도움이 될 수 있습니다.
+ **데이터 정리 및 아카이브** - 더 이상 사용되지 않거나 불필요한 데이터를 검토 및 삭제하여 나중에 사용할 수 있도록 OID를 확보하거나 데이터를 보관합니다. 다음 제한을 고려하세요.
  + 향후 정리가 항상 가능한 것은 아니므로 확장성이 제한적입니다.
  + 결과 데드 튜플을 제거하는 장기 실행 VACUUM 작업입니다.
+ **새 테이블에 쓰기** - 향후 삽입을 위해 새 테이블을 생성하고 `UNION ALL` 뷰를 사용하여 쿼리를 위해 이전 데이터와 새 데이터를 결합합니다. 이 보기는 이전 테이블과 새 테이블의 결합된 데이터를 표시하므로 쿼리가 단일 테이블로 액세스할 수 있습니다. 다음 제한을 고려하세요.
  + 이전 테이블을 업데이트해도 OID가 소진될 수 있습니다.
+ **파티션 또는 샤드** - 확장성과 성능을 높이기 위해 테이블 또는 샤드 데이터를 파티셔닝합니다. 다음 제한을 고려하세요.
  + 쿼리 로직 및 유지 관리의 복잡성이 증가하여 분할된 데이터를 올바르게 처리하기 위해 애플리케이션을 변경해야 할 수 있습니다.

## 모니터링
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.Monitoring"></a>

### 시스템 테이블 사용
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.SystemTables"></a>

PostgreSQL의 시스템 테이블을 사용하여 OID 사용량 증가를 모니터링할 수 있습니다.

**주의**  
TOAST 테이블의 OID 수에 따라 완료하는 데 시간이 걸릴 수 있습니다. 영향을 최소화하려면 업무 외 시간에 모니터링을 예약하는 것이 좋습니다.

다음 익명 블록은 각 TOAST 테이블에 사용된 고유 OID 수를 계산하고 상위 테이블 정보를 표시합니다.

```
DO $$
DECLARE
    r record;
    o bigint;
    parent_table text;
    parent_schema text;
BEGIN
    SET LOCAL client_min_messages TO notice;
    FOR r IN
    SELECT
        c.oid,
        c.oid::regclass AS toast_table
    FROM
        pg_class c
    WHERE
        c.relkind = 't'
        AND c.relowner != 10 LOOP
            -- Fetch the number of distinct used OIDs (chunk IDs) from the TOAST table
            EXECUTE 'SELECT COUNT(DISTINCT chunk_id) FROM ' || r.toast_table INTO o;
            -- If there are used OIDs, find the associated parent table and its schema
            IF o <> 0 THEN
                SELECT
                    n.nspname,
                    c.relname INTO parent_schema,
                    parent_table
                FROM
                    pg_class c
                    JOIN pg_namespace n ON c.relnamespace = n.oid
                WHERE
                    c.reltoastrelid = r.oid;
                -- Raise a concise NOTICE message
                RAISE NOTICE 'Parent schema: % | Parent table: % | Toast table: % | Number of used OIDs: %', parent_schema, parent_table, r.toast_table, TO_CHAR(o, 'FM9,999,999,999,999');
            END IF;
        END LOOP;
END
$$;
```

TOAST 테이블별로 OID 사용량 통계를 표시하는 출력 예제:

```
NOTICE:  Parent schema: public | Parent table: my_table | Toast table: pg_toast.pg_toast_16559 | Number of used OIDs: 45,623,317
NOTICE:  Parent schema: public | Parent table: my_table1 | Toast table: pg_toast.pg_toast_45639925 | Number of used OIDs: 10,000
NOTICE:  Parent schema: public | Parent table: my_table2 | Toast table: pg_toast.pg_toast_45649931 | Number of used OIDs: 1,000,000
DO
```

다음 익명 블록은 비어 있지 않은 각 TOAST 테이블에 할당된 최대 OID를 검색합니다.

```
DO $$
DECLARE
    r record;
    o bigint;
    parent_table text;
    parent_schema text;
BEGIN
    SET LOCAL client_min_messages TO notice;
    FOR r IN
    SELECT
        c.oid,
        c.oid::regclass AS toast_table
    FROM
        pg_class c
    WHERE
        c.relkind = 't'
        AND c.relowner != 10 LOOP
            -- Fetch the max(chunk_id) from the TOAST table
            EXECUTE 'SELECT max(chunk_id) FROM ' || r.toast_table INTO o;
            -- If there's at least one TOASTed chunk, find the associated parent table and its schema
            IF o IS NOT NULL THEN
                SELECT
                    n.nspname,
                    c.relname INTO parent_schema,
                    parent_table
                FROM
                    pg_class c
                    JOIN pg_namespace n ON c.relnamespace = n.oid
                WHERE
                    c.reltoastrelid = r.oid;
                -- Raise a concise NOTICE message
                RAISE NOTICE 'Parent schema: % | Parent table: % | Toast table: % | Max chunk_id: %', parent_schema, parent_table, r.toast_table, TO_CHAR(o, 'FM9,999,999,999,999');
            END IF;
        END LOOP;
END
$$;
```

TOAST 테이블의 최대 청크 ID를 표시하는 출력 예제:

```
NOTICE:  Parent schema: public | Parent table: my_table | Toast table: pg_toast.pg_toast_16559 | Max chunk_id: 45,639,907
NOTICE:  Parent schema: public | Parent table: my_table1 | Toast table: pg_toast.pg_toast_45639925 | Max chunk_id: 45,649,929
NOTICE:  Parent schema: public | Parent table: my_table2 | Toast table: pg_toast.pg_toast_45649931 | Max chunk_id: 46,649,935
DO
```

### 성능 개선 도우미 사용
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.PerformanceInsights"></a>

대기 이벤트 `LWLock:buffer_io` 및 `LWLock:OidGenLock`은 새 객체 식별자(OID)를 할당해야 하는 작업 중에 Performance Insights에 표시됩니다. 이러한 이벤트에 대한 높은 평균 활성 세션(AAS)은 일반적으로 OID 할당 및 리소스 관리 중에 경합을 가리킵니다. 이는 데이터 이탈이 높거나, 대규모 데이터 사용량이 많거나, 객체를 자주 생성하는 환경에서 특히 일반적입니다.

#### LWLock:buffer\$1io
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.LWLockBufferIO"></a>

`LWLock:buffer_io`는 PostgreSQL 세션이 공유 버퍼의 I/O 작업이 완료될 때까지 대기할 때 발생하는 대기 이벤트입니다. 이는 일반적으로 데이터베이스가 디스크의 데이터를 메모리로 읽거나 수정된 페이지를 메모리에서 디스크로 쓸 때 발생합니다. `BufferIO` 대기 이벤트는 I/O 작업이 진행되는 동안 여러 프로세스가 동일한 버퍼에 액세스하거나 수정하지 못하도록 하여 일관성을 보장합니다. 이 대기 이벤트가 높게 발생하면 디스크 병목 현상 또는 데이터베이스 워크로드의 과도한 I/O 활동을 나타낼 수 있습니다.

TOAST 작업 중에 다음을 수행합니다.
+ PostgreSQL은 대형 객체에 OID를 할당하고 TOAST 테이블의 인덱스를 스캔하여 고유성을 보장합니다.
+ 대형 TOAST 인덱스는 OID 고유성을 확인하기 위해 여러 페이지에 액세스해야 할 수 있습니다. 이로 인해 특히 버퍼 풀이 필요한 모든 페이지를 캐싱할 수 없는 경우, 디스크 I/O가 증가합니다.

인덱스의 크기는 이러한 작업 중에 액세스해야 하는 버퍼 페이지 수에 직접적인 영향을 미칩니다. 인덱스가 팽창하지 않더라도 특히 동시성이 높거나 이탈이 많은 환경에서는 얇은 크기로 인해 버퍼 I/O가 증가할 수 있습니다. 자세한 내용은 [LWLock:BufferIO 대기 이벤트 문제 해결 가이드](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/apg-waits.lwlockbufferio.html)를 참조하세요.

#### LWLock:OidGenLock
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.LWLockOidGenLock"></a>

`OidGenLock`은 PostgreSQL 세션이 새 객체 식별자(OID) 할당을 기다리고 있을 때 발생하는 대기 이벤트입니다. 이 잠금을 사용하면 OID가 순차적으로 안전하게 생성되므로 한 번에 하나의 프로세스만 OID를 생성할 수 있습니다.

TOAST 작업 중에 다음을 수행합니다.
+ **TOAST 테이블의 청크에 대한 OID 할당** - PostgreSQL은 대용량 데이터 레코드를 관리할 때 TOAST 테이블의 청크에 OID를 할당합니다. 시스템 카탈로그에서 충돌을 방지하려면 각 OID가 고유해야 합니다.
+ **높은 동시성** - OID 생성기에 대한 액세스는 순차적이므로 여러 세션이 동시에 OID가 필요한 객체를 생성하는 경우 `OidGenLock`에 대한 경합이 발생할 수 있습니다. 이렇게 하면 세션이 OID 할당이 완료될 때까지 기다릴 가능성이 높아집니다.
+ **시스템 카탈로그 액세스 종속성** - OID를 할당하려면 `pg_class` 및 `pg_type`과 같은 공유 시스템 카탈로그 테이블을 업데이트해야 합니다. 이러한 테이블에 과도한 활동이 발생하는 경우(DDL 작업이 잦음) `OidGenLock`에 대한 잠금 경합이 증가할 수 있습니다.
+ **높은 OID 할당 수요** - 대규모 데이터 레코드가 있는 TOAST 과중한 워크로드에는 일정한 OID 할당이 필요하므로 경합이 증가합니다.

OID 경합을 높이는 추가 요인:
+ **빈번한 객체 생성** - 임시 테이블과 같은 객체를 자주 생성 및 삭제하는 워크로드는 글로벌 OID 카운터에서 경합을 증폭합니다.
+ **글로벌 카운터 잠금** - 글로벌 OID 카운터는 고유성을 보장하기 위해 순차적으로 액세스되므로 동시성이 높은 환경에서 단일 경합 지점을 생성합니다.

## RDS for PostgreSQL에서 지원되는 로깅 메커니즘 작업
<a name="Appendix.PostgreSQL.CommonDBATasks.Auditing"></a>

PostgreSQL DB 인스턴스에 발생하는 기록 활동을 설정할 수 있는 파라미터, 확장 및 기타 구성 항목이 몇 가지 있습니다. 여기에는 다음이 포함됩니다.
+ `log_statement` 파라미터는 PostgreSQL 데이터베이스에서 사용자 활동 로그에 사용할 수 있습니다. RDS for PostgreSQL 로깅 및 로그를 모니터링하는 방법에 대한 자세한 내용은 [ RDS for PostgreSQL 데이터베이스 로그 파일](USER_LogAccess.Concepts.PostgreSQL.md) 섹션을 참조하세요.
+ `rds.force_admin_logging_level` 파라미터는 Amazon RDS 내부 사용자(rdsadmin)가 DB 인스턴스의 데이터베이스에서 수행한 작업을 기록합니다. PostgreSQL 오류 로그에 출력을 기록합니다. 허용되는 값은 `disabled`, `debug5`, `debug4`, `debug3`, `debug2`, `debug1`, `info`, `notice`, `warning`, `error`, 로그, `fatal` 및 `panic`입니다. 기본값은 `disabled`입니다.
+ PostgreSQL 오류 로그에서 다양한 autovacuum 작업을 캡처하도록 `rds.force_autovacuum_logging_level` 파라미터를 설정할 수 있습니다. 자세한 내용은 [autovacuum 및 vacuum 활동 로그](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.Logging.md) 섹션을 참조하세요.
+ PostgreSQL Audit(pgAudit) 확장 프로그램은 세션 수준 또는 객체 수준에서 활동을 캡처하도록 설치 및 구성할 수 있습니다. 자세한 내용은 [pgAudit를 사용하여 데이터베이스 활동 로깅](Appendix.PostgreSQL.CommonDBATasks.pgaudit.md) 섹션을 참조하세요.
+ `log_fdw` 확장을 통해 SQL을 사용하여 데이터베이스 엔진 로그에 액세스할 수 있습니다. 자세한 정보는 [log\$1fdw 확장으로 SQL을 사용하여 DB 로그에 액세스](CHAP_PostgreSQL.Extensions.log_fdw.md)의 내용을 참조하세요.
+ `pg_stat_statements` 라이브러리가 RDS for PostgreSQL 버전 10 이상의 `shared_preload_libraries` 파라미터에 대한 기본값으로 지정됩니다. 실행 중인 쿼리를 분석할 때 사용할 수 있는 라이브러리입니다. `pg_stat_statements`가 DB 파라미터 그룹에 설정되는 것을 확인하세요. 이 라이브러리에서 제공하는 정보를 사용하여 RDS for PostgreSQL DB 인스턴스를 모니터링하는 방법에 대한 자세한 내용은 [RDS PostgreSQL에 대한 SQL 통계](USER_PerfInsights.UsingDashboard.AnalyzeDBLoad.AdditionalMetrics.PostgreSQL.md) 섹션을 참조하세요.
+ `log_hostname` 파라미터는 각 클라이언트 연결의 호스트 이름을 로그에 캡처합니다. RDS for PostgreSQL 버전 12 이상에서 이 파라미터는 기본적으로 `off`로 설정됩니다. 이 파라미터를 켰다면 세션 연결 시간을 모니터링해야 합니다. 이 파라미터를 켜면 서비스는 도메인 이름 시스템(DNS) 역방향 조회 요청을 사용하여, 연결할 클라이언트의 호스트 이름을 얻은 다음 PostgreSQL 로그에 추가합니다. 이렇게 되면 세션 연결 중에 상당한 영향이 발생합니다. 이 파라미터는 문제를 해결해야 할 때만 켜는 것이 좋습니다.

일반적으로 로깅의 목적은 DBA가 성능을 모니터링하고 튜닝하고 문제를 해결할 수 있도록 하는 것입니다. 대부분의 로그가 Amazon CloudWatch 또는 성능 개선 도우미로 자동 업로드됩니다. 여기서 로그는 DB 인스턴스에 대한 전체 지표를 제공하기 위해 정렬되고 그룹화됩니다. Amazon RDS 모니터링 및 지표에 대한 자세한 내용은 [Amazon RDS 인스턴스에서 지표 모니터링](CHAP_Monitoring.md) 섹션을 참조하세요.

# PostgreSQL을 사용한 임시 파일 관리
<a name="PostgreSQL.ManagingTempFiles"></a>

PostgreSQL에서 복잡한 쿼리는 여러 가지 정렬 또는 해시 연산을 동시에 수행할 수 있으며, 각 연산은 인스턴스 메모리를 사용하여 [https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-WORK-MEM](https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-WORK-MEM) 파라미터에 지정된 값까지 결과를 저장합니다. 인스턴스 메모리가 충분하지 않은 경우 결과를 저장하기 위한 임시 파일이 생성됩니다. 이러한 임시 파일은 쿼리 실행을 완료하기 위해 디스크에 기록됩니다. 나중에 이러한 파일은 쿼리가 완료된 후 자동으로 제거됩니다. RDS for PostgreSQL에서는 이러한 파일이 데이터 볼륨의 Amazon EBS에 저장됩니다. 자세한 내용은 [Amazon RDS DB 인스턴스 스토리지](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Storage.html)를 참조하세요. CloudWatch에 게시되는 `FreeStorageSpace` 지표를 계속 모니터링하여 DB 인스턴스에 충분한 스토리지 여유 공간이 있는지 확인합니다. 자세한 내용은 [https://repost.aws/knowledge-center/storage-full-rds-cloudwatch-alarm](https://repost.aws/knowledge-center/storage-full-rds-cloudwatch-alarm) 단원을 참조하세요. 

임시 파일 사용량을 늘리는 다중 동시 쿼리가 포함된 워크로드에서는 Amazon RDS 최적화된 읽기 인스턴스를 사용하는 것이 좋습니다. 이러한 인스턴스는 SSD(Solid State Drive) 블록 스토리지에 기반한 NVMe(Non-Volatile Memory Express)를 사용하여 임시 파일을 배치할 수 있습니다. 자세한 내용은 [Amazon RDS Optimized Reads로 RDS for PostgreSQL 쿼리 성능 개선](USER_PostgreSQL.optimizedreads.md) 섹션을 참조하세요.

다음과 같은 파라미터와 함수를 사용하여 인스턴스의 임시 파일을 관리할 수 있습니다.
+ **[https://www.postgresql.org/docs/current/runtime-config-resource.html#RUNTIME-CONFIG-RESOURCE-DISK](https://www.postgresql.org/docs/current/runtime-config-resource.html#RUNTIME-CONFIG-RESOURCE-DISK)** - 이 파라미터는 temp\$1files 크기(KB)를 초과하는 모든 쿼리를 취소합니다. 이러한 한도는 쿼리가 무한으로 실행되어 임시 파일이 디스크 공간을 사용하는 현상을 방지합니다. `log_temp_files` 파라미터의 결과를 사용하여 값을 추정할 수 있습니다. 가장 좋은 방법은 워크로드 동작을 검사하고 추정치에 따라 한도를 설정하는 것입니다. 다음 예는 한도를 초과했을 때 쿼리가 취소되는 방식을 보여줍니다.

  ```
  postgres=>select * from pgbench_accounts, pg_class, big_table;
  ```

  ```
  ERROR: temporary file size exceeds temp_file_limit (64kB)
  ```
+ **[https://www.postgresql.org/docs/current/runtime-config-logging.html#GUC-LOG-TEMP-FILES](https://www.postgresql.org/docs/current/runtime-config-logging.html#GUC-LOG-TEMP-FILES)** - 이 파라미터는 세션의 임시 파일이 제거될 경우 postgresql.log로 메시지를 보냅니다. 이 파라미터는 쿼리가 성공적으로 완료된 후 로그를 생성합니다. 따라서 활성 상태의 장기 실행 쿼리의 문제를 해결하는 데에는 도움이 되지 않을 수도 있습니다.

  다음 예시에서는 쿼리가 성공적으로 완료되었을 때 임시 파일이 정리되는 동안 항목이 postgresql.log 파일에 기록되는 것을 보여줍니다.

  ```
                      
  2023-02-06 23:48:35 UTC:205.251.233.182(12456):adminuser@postgres:[31236]:LOG:  temporary file: path "base/pgsql_tmp/pgsql_tmp31236.5", size 140353536
  2023-02-06 23:48:35 UTC:205.251.233.182(12456):adminuser@postgres:[31236]:STATEMENT:  select a.aid from pgbench_accounts a, pgbench_accounts b where a.bid=b.bid order by a.bid limit 10;
  2023-02-06 23:48:35 UTC:205.251.233.182(12456):adminuser@postgres:[31236]:LOG:  temporary file: path "base/pgsql_tmp/pgsql_tmp31236.4", size 180428800
  2023-02-06 23:48:35 UTC:205.251.233.182(12456):adminuser@postgres:[31236]:STATEMENT:  select a.aid from pgbench_accounts a, pgbench_accounts b where a.bid=b.bid order by a.bid limit 10;
  ```
+ **[https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADMIN-GENFILE](https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADMIN-GENFILE)** - RDS for PostgreSQL 13 이상에서 제공되는 이 함수를 사용하면 현재 임시 파일 사용량을 확인할 수 있습니다. 완료된 쿼리는 함수 결과에 나타나지 않습니다. 다음 예제에서는 이 함수의 결과를 볼 수 있습니다.

  ```
  postgres=>select * from pg_ls_tmpdir();
  ```

  ```
        name       |    size    |      modification
  -----------------+------------+------------------------
   pgsql_tmp8355.1 | 1072250880 | 2023-02-06 22:54:56+00
   pgsql_tmp8351.0 | 1072250880 | 2023-02-06 22:54:43+00
   pgsql_tmp8327.0 | 1072250880 | 2023-02-06 22:54:56+00
   pgsql_tmp8351.1 |  703168512 | 2023-02-06 22:54:56+00
   pgsql_tmp8355.0 | 1072250880 | 2023-02-06 22:54:00+00
   pgsql_tmp8328.1 |  835031040 | 2023-02-06 22:54:56+00
   pgsql_tmp8328.0 | 1072250880 | 2023-02-06 22:54:40+00
  (7 rows)
  ```

  ```
  postgres=>select query from pg_stat_activity where pid = 8355;
                  
  query
  ----------------------------------------------------------------------------------------
  select a.aid from pgbench_accounts a, pgbench_accounts b where a.bid=b.bid order by a.bid
  (1 row)
  ```

  파일 이름에는 임시 파일을 생성한 세션의 처리 ID(PID)가 포함됩니다. 다음 예와 같은 고급 쿼리는 각 PID에 대한 임시 파일의 합계를 수행합니다.

  ```
  postgres=>select replace(left(name, strpos(name, '.')-1),'pgsql_tmp','') as pid, count(*), sum(size) from pg_ls_tmpdir() group by pid;
  ```

  ```
   pid  | count |   sum
  ------+-------------------
   8355 |     2 | 2144501760
   8351 |     2 | 2090770432
   8327 |     1 | 1072250880
   8328 |     2 | 2144501760
  (4 rows)
  ```
+ **`[ pg\$1stat\$1statements](https://www.postgresql.org/docs/current/pgstatstatements.html)`** - pg\$1stat\$1statements 파라미터를 활성화하면 호출당 평균 임시 파일 사용량을 볼 수 있습니다. 쿼리의 query\$1id를 식별하고 이를 사용하여 다음 예와 같이 임시 파일 사용량을 검사할 수 있습니다.

  ```
  postgres=>select queryid from pg_stat_statements where query like 'select a.aid from pgbench%';
  ```

  ```
         queryid
  ----------------------
   -7170349228837045701
  (1 row)
  ```

  ```
  postgres=>select queryid, substr(query,1,25), calls, temp_blks_read/calls temp_blks_read_per_call, temp_blks_written/calls temp_blks_written_per_call from pg_stat_statements where queryid = -7170349228837045701;
  ```

  ```
         queryid        |          substr           | calls | temp_blks_read_per_call | temp_blks_written_per_call
  ----------------------+---------------------------+-------+-------------------------+----------------------------
   -7170349228837045701 | select a.aid from pgbench |    50 |                  239226 |                     388678
  (1 row)
  ```
+ **`[Performance Insights](https://aws.amazon.com/rds/performance-insights/)`** - 성능 개선 도우미 대시보드에서 **temp\$1bytes** 및 **temp\$1files** 메트릭을 켜서 임시 파일 사용량을 확인할 수 있습니다. 그런 다음, 이 두 지표의 평균을 확인하고 두 지표가 쿼리 워크로드에 어떻게 상응하는지 확인할 수 있습니다. 성능 개선 도우미 내부의 보기에는 임시 파일을 생성 중인 쿼리가 구체적으로 표시되지 않습니다. 그러나 성능 개선 도우미를 `pg_ls_tmpdir`에 대해 표시된 쿼리와 결합하면 쿼리 워크로드의 문제를 해결하고, 분석하고, 변경 사항을 확인할 수 있습니다.

  성능 개선 도우미를 사용하여 지표를 분석하고 쿼리를 분석하는 방법에 대한 자세한 내용은 [성능 개선 도우미 대시보드를 사용한 지표 분석](USER_PerfInsights.UsingDashboard.md) 섹션을 참조하세요.

  성능 개선 도우미를 사용하여 임시 파일 사용량을 보는 예제는 [성능 개선 도우미를 사용하여 임시 파일 사용량 확인](PostgreSQL.ManagingTempFiles.Example.md) 섹션을 참조하세요.

# 성능 개선 도우미를 사용하여 임시 파일 사용량 확인
<a name="PostgreSQL.ManagingTempFiles.Example"></a>

성능 개선 도우미를 통해 지표 **temp\$1bytes** 및 **temp\$1files**를 설정하여 임시 파일 사용량을 볼 수 있습니다. 성능 개선 도우미 보기에는 임시 파일을 생성하는 특정 쿼리가 표시되지 않지만, `pg_ls_tmpdir`에 대해 표시된 쿼리와 성능 개선 도우미를 결합하면 쿼리 워크로드를 분석하고, 변경 사항을 확인하고, 문제를 해결할 수 있습니다.

1. 성능 개선 도우미 대시보드에서 **지표 관리**를 선택합니다.

1. 다음 이미지에 나와 있는 것처럼 **데이터베이스 지표**를 선택하고, **temp\$1bytes** 및 **temp\$1files**를 선택합니다.  
![\[지표가 그래프로 표시됩니다.\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/images/rpg_mantempfiles_metrics.png)

1. **상위 SQL** 탭에서 **기본 설정** 아이콘을 선택합니다.

1. **기본 설정** 창에서 **상위 SQL** 탭에 표시할 다음 통계를 켜고 **계속**을 선택합니다.
   + 임시 쓰기/초
   + 임시 읽기/초
   + 임시 대량 쓰기/호출
   + 임시 대량 읽기/호출

1. 다음 예제에 나온 것처럼, 임시 파일은 `pg_ls_tmpdir`에 대해 표시된 쿼리와 함께 통합될 때 분할됩니다.  
![\[임시 파일 사용량을 표시하는 쿼리.\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/images/rpg_mantempfiles_query.png)

`IO:BufFileRead` 및 `IO:BufFileWrite` 이벤트는 대개 워크로드의 상위 쿼리에서 임시 파일이 생성될 때 발생합니다. 데이터베이스 부하 및 상위 SQL 섹션의 AAS(상위 활성 세션)를 검토하여 `IO:BufFileRead` 및 `IO:BufFileWrite`에서 대기 중인 상위 쿼리를 식별하는 데 성능 개선 도우미를 사용할 수 있습니다.

![\[그래프에 IO:BufFileRead 및 IO:BufFileWrite가 표시되어 있습니다.\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/images/perfinsights_IOBufFile.png)


성능 개선 도우미를 사용하여 상위 쿼리와 대기 이벤트에서 부하를 분석하는 방법에 대한 자세한 내용은 [상위 SQL(Top SQL) 탭 개요](USER_PerfInsights.UsingDashboard.AnalyzeDBLoad.AdditionalMetrics.md#USER_PerfInsights.UsingDashboard.Components.AvgActiveSessions.TopLoadItemsTable.TopSQL) 단원을 참조하세요. 임시 파일 사용량 및 관련 대기 이벤트를 늘리는 쿼리를 식별하고 조정해야 합니다. 이러한 대기 이벤트 및 수정에 대한 자세한 내용은 [IO:BufFileRead 및 IO:BufFileWrite](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/wait-event.iobuffile.html)를 참조하세요.

**참고**  
이 [https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-WORK-MEM](https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-WORK-MEM) 파라미터는 정렬 작업의 메모리가 부족하여 결과가 임시 파일에 기록되는 시점을 제어합니다. 이 파라미터의 설정을 기본값보다 높게 변경하면 모든 데이터베이스 세션에서 더 많은 메모리를 사용할 수 있으므로 변경하지 않는 것이 좋습니다. 또한 복잡한 조인 및 정렬을 수행하는 단일 세션에서는 각 작업이 메모리를 사용하는 병렬 작업을 수행할 수 있습니다.  
여러 조인 및 정렬이 포함된 대용량 보고서가 있을 경우 `SET work_mem` 명령을 사용하여 세션 수준에서 이 파라미터를 설정하는 것이 가장 좋습니다. 그러면 변경 사항이 현재 세션에만 적용되고 값이 전체적으로 변경되지 않습니다.

## pgBadger를 사용한 PostgreSQL의 로그 분석
<a name="Appendix.PostgreSQL.CommonDBATasks.Badger"></a>

[pgBadger](http://dalibo.github.io/pgbadger/) 등의 로그 분석기를 사용하여 PostgreSQL 로그를 분석할 수 있습니다. pgBadger 문서에는 %l 패턴(세션 또는 프로세스의 로그 라인)은 접두사에 포함되어야 한다고 나와 있습니다. 그러나 현재 RDS `log_line_prefix`를 pgBadger에 파라미터로 사용하더라도 여전히 보고서를 생성해야 합니다.

예를 들어 다음 명령은 pgBadger를 사용하여 2014-02-04 일자의 Amazon RDS for PostgreSQL 로그 파일을 정확한 형식으로 나타내고 있습니다.

```
./pgbadger -f stderr -p '%t:%r:%u@%d:[%p]:' postgresql.log.2014-02-04-00 
```

## PGSnapper를 사용하여 PostgreSQL 모니터링
<a name="Appendix.PostgreSQL.CommonDBATasks.Snapper"></a>

PGSnapper를 사용하여 Amazon RDS for PostgreSQL 성능 관련 통계 및 지표의 주기적인 수집을 지원할 수 있습니다. 자세한 내용은 [Monitor Amazon RDS for PostgreSQL performance using PGSnapper](https://aws.amazon.com/blogs/database/monitor-amazon-rds-for-postgresql-and-amazon-aurora-postgresql-performance-using-pgsnapper/)(PGSnapper를 사용하여 Amazon RDS for PostgreSQL 성능 모니터링)를 참조하세요.

# RDS for PostgreSQL에서 사용자 지정 캐스트 관리
<a name="PostgreSQL.CustomCasts"></a>

PostgreSQL의 **유형 캐스팅**은 값을 한 데이터 유형에서 다른 데이터 유형으로 변환하는 프로세스입니다. PostgreSQL은 대다수 일반적인 변환을 위한 내장 캐스트를 제공하지만 사용자 지정 캐스트를 생성하여 특정 유형 변환의 작동 방식을 정의할 수도 있습니다.

캐스트는 한 데이터 유형에서 다른 데이터 유형으로 변환하는 방법을 지정합니다. 예를 들어 텍스트 `'123'`을 정수 `123`으로 변환하거나 숫자 `45.67`을 `'45.67'`로 변환합니다.

PostgreSQL 캐스팅 개념 및 구문에 대한 자세한 내용은 [PostgreSQL CREATE CAST 설명서](https://www.postgresql.org/docs/current/sql-createcast.html)를 참조하세요.

RDS for PostgreSQL 버전 13.23, 14.20, 15.15, 16.11, 17.7 및 18.1부터 rds\$1casts 확장을 사용하여 내장 유형에 대한 추가 캐스트를 설치할 수 있으며, 사용자 지정 유형에 대한 자체 캐스트를 생성할 수도 있습니다.

**Topics**
+ [rds\$1casts 확장 설치 및 사용](#PostgreSQL.CustomCasts.Installing)
+ [지원되는 캐스트](#PostgreSQL.CustomCasts.Supported)
+ [캐스트 생성 또는 삭제](#PostgreSQL.CustomCasts.Creating)
+ [적절한 컨텍스트 전략을 사용하여 사용자 지정 캐스트 생성](#PostgreSQL.CustomCasts.BestPractices)

## rds\$1casts 확장 설치 및 사용
<a name="PostgreSQL.CustomCasts.Installing"></a>

`rds_casts` 확장을 생성하려면 RDS for PostgreSQL DB 인스턴스에 `rds_superuser`로 연결하고 다음 명령을 실행합니다.

```
CREATE EXTENSION IF NOT EXISTS rds_casts;
```

## 지원되는 캐스트
<a name="PostgreSQL.CustomCasts.Supported"></a>

사용자 지정 캐스트를 사용하려는 각 데이터베이스에서 확장을 생성합니다. 확장을 생성한 후 다음 명령을 사용하여 사용 가능한 모든 캐스트를 봅니다.

```
SELECT * FROM rds_casts.list_supported_casts();
```

이 함수는 사용 가능한 캐스트 조합(소스 유형, 대상 유형, 강제 컨텍스트 및 캐스트 함수)을 나열합니다. 예를 들어 `implicit` 캐스트로 `text`에서 `numeric`으로의 변환을 생성하려는 경우 다음 쿼리를 사용하여 캐스트를 생성할 수 있는지 확인할 수 있습니다.

```
SELECT * FROM rds_casts.list_supported_casts()
WHERE source_type = 'text' AND target_type = 'numeric';
 id | source_type | target_type |          qualified_function          | coercion_context
----+-------------+-------------+--------------------------------------+------------------
 10 | text        | numeric     | rds_casts.rds_text_to_numeric_custom | implicit
 11 | text        | numeric     | rds_casts.rds_text_to_numeric_custom | assignment
 13 | text        | numeric     | rds_casts.rds_text_to_numeric_custom | explicit
 20 | text        | numeric     | rds_casts.rds_text_to_numeric_inout  | implicit
 21 | text        | numeric     | rds_casts.rds_text_to_numeric_inout  | assignment
 23 | text        | numeric     | rds_casts.rds_text_to_numeric_inout  | explicit
```

rds\$1casts 확장은 각 캐스트에 대해 두 가지 유형의 변환 함수를 제공합니다.
+ *\$1inout 함수* - PostgreSQL의 표준 I/O 변환 메커니즘을 사용하며, INOUT 메서드로 생성된 캐스트와 동일하게 동작합니다.
+ *\$1custom 함수* - 변환 오류를 방지하기 위해 빈 문자열을 NULL 값으로 변환하는 등 엣지 사례를 처리하는 향상된 변환 로직을 제공합니다.

`inout` 함수는 PostgreSQL의 기본 캐스팅 동작을 재현하는 한편, `custom` 함수는 빈 문자열을 정수로 변환하는 등 표준 INOUT 캐스팅으로는 불가능한 시나리오를 처리하여 이 기능을 확장합니다.

## 캐스트 생성 또는 삭제
<a name="PostgreSQL.CustomCasts.Creating"></a>

다음 두 가지 방법을 사용하여 지원되는 캐스트를 생성하고 삭제할 수 있습니다.

### 캐스트 생성
<a name="PostgreSQL.CustomCasts.Creating.Methods"></a>

**방법 1: 기본 CREATE CAST 명령 사용**

```
CREATE CAST (text AS numeric)
WITH FUNCTION rds_casts.rds_text_to_numeric_custom
AS IMPLICIT;
```

**방법 2: rds\$1casts.create\$1cast 함수 사용**

```
SELECT rds_casts.create_cast(10);
```

`create_cast` 함수는 `list_supported_casts()` 출력에서 ID를 가져옵니다. 이 방법은 더 간단하며 올바른 함수와 컨텍스트 조합을 사용할 수 있도록 합니다. 이 ID는 여러 postgres 버전에서 동일하게 유지됩니다.

캐스트가 성공적으로 생성되었는지 확인하려면 pg\$1cast 시스템 카탈로그를 쿼리합니다.

```
SELECT oid, castsource::regtype, casttarget::regtype, castfunc::regproc, castcontext, castmethod
FROM pg_cast
WHERE castsource = 'text'::regtype AND casttarget = 'numeric'::regtype;
  oid   | castsource | casttarget |               castfunc               | castcontext | castmethod
--------+------------+------------+--------------------------------------+-------------+------------
 356372 | text       | numeric    | rds_casts.rds_text_to_numeric_custom | i           | f
```

`castcontext` 열에는 EXPLICIT을 나타내는 `e`, ASSIGNMENT를 나타내는 `a`, IMPLICIT을 나타내는 `i`가 표시됩니다.

### 캐스트 삭제
<a name="PostgreSQL.CustomCasts.Dropping"></a>

**방법 1: DROP CAST 명령 사용**

```
DROP CAST IF EXISTS (text AS numeric);
```

**방법 2: rds\$1casts.drop\$1cast 함수 사용**

```
SELECT rds_casts.drop_cast(10);
```

`drop_cast` 함수는 캐스트를 생성할 때 사용된 것과 동일한 ID를 사용합니다. 이 방법을 통해 해당 ID로 생성된 정확한 캐스트를 삭제할 수 있습니다.

## 적절한 컨텍스트 전략을 사용하여 사용자 지정 캐스트 생성
<a name="PostgreSQL.CustomCasts.BestPractices"></a>

정수 유형에 대해 여러 캐스트를 생성할 때 모든 캐스트가 IMPLICIT으로 생성되면 연산자 모호성 오류가 발생할 수 있습니다. 다음 예제에서는 텍스트에서 서로 다른 정수 너비로 두 개의 암시적 캐스트를 생성하여 이 문제를 보여줍니다.

```
-- Creating multiple IMPLICIT casts causes ambiguity
postgres=> CREATE CAST (text AS int4) WITH FUNCTION rds_casts.rds_text_to_int4_custom(text) AS IMPLICIT;
CREATE CAST
postgres=> CREATE CAST (text AS int8) WITH FUNCTION rds_casts.rds_text_to_int8_custom(text) AS IMPLICIT;
CREATE CAST

postgres=> CREATE TABLE test_cast(col int);
CREATE TABLE
postgres=> INSERT INTO test_cast VALUES ('123'::text);
INSERT 0 1
postgres=> SELECT * FROM test_cast WHERE col='123'::text;
ERROR:  operator is not unique: integer = text
LINE 1: SELECT * FROM test_cast WHERE col='123'::text;
                                         ^
HINT:  Could not choose a best candidate operator. You might need to add explicit type casts.
```

이 오류는 PostgreSQL이 정수 열을 텍스트 값과 비교할 때 사용할 암시적 캐스팅을 결정할 수 없기 때문에 발생합니다. int4와 int8 암시적 캐스트가 모두 유효한 후보이므로 모호성이 발생합니다.

이 연산자 모호성을 방지하려면 작은 정수 너비에는 ASSIGNMENT 컨텍스트를 사용하고 큰 정수 너비에는 IMPLICIT 컨텍스트를 사용합니다.

```
-- Use ASSIGNMENT for smaller integer widths
CREATE CAST (text AS int2)
WITH FUNCTION rds_casts.rds_text_to_int2_custom(text)
AS ASSIGNMENT;

CREATE CAST (text AS int4)
WITH FUNCTION rds_casts.rds_text_to_int4_custom(text)
AS ASSIGNMENT;

-- Use IMPLICIT for larger integer widths
CREATE CAST (text AS int8)
WITH FUNCTION rds_casts.rds_text_to_int8_custom(text)
AS IMPLICIT;

postgres=> INSERT INTO test_cast VALUES ('123'::text);
INSERT 0 1
postgres=> SELECT * FROM test_cast WHERE col='123'::text;
 col
-----
 123
(1 row)
```

이 전략에서는 int8 캐스트만 암시적이므로 PostgreSQL이 사용할 캐스트를 명확하게 결정할 수 있습니다.

# RDS for PostgreSQL의 병렬 쿼리 모범 사례
<a name="PostgreSQL.ParallelQueries"></a>

병렬 쿼리 실행은 PostgreSQL의 기능으로, 단일 SQL 쿼리를 더 작은 작업으로 나누어 여러 백그라운드 작업자 프로세스로 동시에 처리할 수 있습니다. PostgreSQL은 단일 백엔드 프로세스에서 쿼리를 완전히 실행하는 대신에 스캔, 조인, 집계 또는 정렬과 같은 쿼리 부분을 여러 CPU 코어에 분산할 수 있습니다. *리더 프로세스*는 이 실행을 조정하고 *병렬 작업자*로부터 결과를 수집합니다.

그러나 대부분의 프로덕션 워크로드, 특히 동시성이 높은 OLTP 시스템의 경우 자동 병렬 쿼리 실행을 비활성화하는 것이 좋습니다. 병렬 처리는 분석 또는 보고 워크로드의 대규모 데이터 세트에 대한 쿼리를 가속화할 수 있지만, 사용량이 많은 프로덕션 환경에서는 이점을 능가하는 상당한 위험을 초래하는 경우가 자주 있습니다.

병렬 실행에도 상당한 오버헤드가 발생합니다. 각 병렬 작업자는 프로세스 포크(메모리 구조 복사 및 프로세스 상태 초기화) 및 인증(`max_connections` 제한에서 연결 슬롯 사용)이 필요한 전체 PostgreSQL 백엔드 프로세스입니다. 또한 각 작업자는 쿼리당 여러 작업자가 있는 정렬 및 해싱 작업의 `work_mem`을 포함하여 자체 메모리를 사용합니다. 메모리 사용량은 빠르게 증가합니다(예: 작업자 4명 × 쿼리당 64MB `work_mem` = 256MB). 따라서 병렬 쿼리는 단일 프로세스 쿼리보다 훨씬 더 많은 시스템 리소스를 사용할 수 있습니다. 제대로 조정하지 않으면 CPU 포화(여러 작업자가 사용 가능한 처리 용량을 초과함), 컨텍스트 전환 증가(운영 체제가 여러 작업자 프로세스 간에 빈번하게 전환되어 오버헤드가 발생하고 처리량이 감소함) 또는 연결 소진(각 병렬 작업자가 연결 슬롯을 사용하므로 작업자가 4명인 단일 쿼리는 총 5개의 연결(리더 1개 \$1 작업자 4개)을 사용하게 되며, 이는 높은 동시성으로 인해 연결 풀을 빠르게 소진시켜 새로운 클라이언트 연결을 차단하고 애플리케이션 오류를 유발할 수 있음)로 이어질 수 있습니다. 이러한 문제는 여러 쿼리가 동시에 병렬 실행을 시도할 수 있는 동시성이 높은 워크로드에서 특히 심각합니다.

PostgreSQL은 예상 비용을 기반으로 병렬 처리를 사용할지 여부를 결정합니다. 경우에 따라 플래너는 실제로는 이상적이지 않더라도 더 저렴한 것으로 보이는 경우 병렬 계획으로 자동 전환할 수 있습니다. 이는 인덱스 통계가 오래된 경우 또는 순차적 스캔이 인덱스 조회보다 더 매력적으로 보이도록 하는 경우에 발생할 수 있습니다. 이러한 동작 때문에 자동 병렬 실행 계획은 때때로 쿼리 성능이나 시스템 안정성에 회귀를 초래할 수 있습니다.

RDS for PostgreSQL에서 병렬 쿼리의 이점을 최대한 활용하려면 워크로드를 기반으로 병렬 쿼리를 테스트 및 조정하고, 시스템 영향을 모니터링하고, 쿼리 수준 제어를 위해 자동 병렬 계획 선택을 비활성화하는 것이 중요합니다.

## 구성 파라미터
<a name="PostgreSQL.ParallelQueries.ConfigurationParameters"></a>

PostgreSQL은 여러 파라미터를 사용하여 병렬 쿼리의 동작과 가용성을 제어합니다. 이를 이해하고 조정하는 것은 예측 가능한 성능을 달성하는 데 매우 중요합니다.


| 파라미터 | 설명 | 기본값 | 
| --- | --- | --- | 
| max\$1parallel\$1workers | 총 실행할 수 있는 백그라운드 작업자 프로세스의 최대 수 | GREATEST(\$1DBInstanceVCPU/2,8) | 
| max\$1parallel\$1workers\$1per\$1gather | 쿼리 계획 노드당 최대 작업자 수(예: Gather당) | 2 | 
| parallel\$1setup\$1cost | 병렬 쿼리 인프라를 시작하기 위한 플래너 비용 추가 | 1000 | 
| parallel\$1tuple\$1cost | 병렬 모드로 처리된 튜플당 비용(플래너 결정에 영향을 줌) | 0.1 | 
| force\$1parallel\$1mode | 플래너가 병렬 계획(off, on, regress)을 테스트하도록 강제 | off | 

### 주요 고려 사항
<a name="PostgreSQL.ParallelQueries.ConfigurationParameters.KeyConsiderations"></a>
+ `max_parallel_workers`는 병렬 작업자의 총 풀을 제어합니다. 너무 낮게 설정하면 일부 쿼리가 직렬 실행으로 돌아갈 수 있습니다.
+ `max_parallel_workers_per_gather`는 단일 쿼리가 사용할 수 있는 작업자 수에 영향을 줍니다. 값이 높을수록 동시성이 증가하지만 리소스 사용량도 증가합니다.
+ `parallel_setup_cost` 및 `parallel_tuple_cost`는 플래너의 비용 모델에 영향을 미칩니다. 이러한 값을 낮추면 병렬 계획을 선택할 가능성이 높아질 수 있습니다.
+ `force_parallel_mode`는 테스트에 유용하지만 필요한 경우가 아니라면 프로덕션 환경에서 사용해서는 안 됩니다.

**참고**  
`max_parallel_workers` 파라미터의 기본값은 수식 `GREATEST($DBInstanceVCPU/2, 8)`를 사용하여 인스턴스 크기를 기반으로 동적으로 계산됩니다. 즉, vCPU가 많을수록 DB 인스턴스를 더 큰 컴퓨팅 크기로 확장하면 사용 가능한 최대 병렬 작업자 수가 자동으로 증가합니다. 따라서 이전에 직렬로 실행되었거나 병렬 처리가 제한된 쿼리는 스케일 업 작업 후 갑자기 더 많은 병렬 작업자를 활용하여 연결 사용량, CPU 사용률 및 메모리 소비가 예기치 않게 증가할 수 있습니다. 컴퓨팅 스케일링 이벤트 후에는 병렬 쿼리 동작을 모니터링하고 필요한 경우 `max_parallel_workers_per_gather`를 조정하여 예측 가능한 리소스 사용량을 유지하는 것이 중요합니다.

## 병렬 쿼리 사용량 식별
<a name="PostgreSQL.ParallelQueries.IdentifyUsage"></a>

쿼리는 데이터 배포 또는 통계에 따라 병렬 계획으로 전환될 수 있습니다. 예제:

```
SELECT count(*) FROM customers WHERE last_login < now() - interval '6 months';
```

이 쿼리는 최근 데이터에 인덱스를 사용하지만 기록 데이터에 대한 병렬 순차 스캔으로 전환할 수 있습니다.

`auto_explain` 모듈을 로드하여 쿼리 실행 계획을 로깅할 수 있습니다. 자세히 알아보려면 AWS 지식 센터에서 [쿼리 실행 계획 로깅에 관한 문서](https://aws.amazon.com/premiumsupport/knowledge-center/rds-postgresql-tune-query-performance/#)를 참조하세요.

을 참조하세요.

병렬 쿼리 관련 대기 이벤트에 대한 [CloudWatch Database Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Database-Insights-Database-Instance-Dashboard.html)를 모니터링할 수 있습니다. 병렬 쿼리 관련 대기 이벤트에 대해 자세히 알아보려면 [IPC:병렬 대기 이벤트](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/apg-ipc-parallel.html)를 살펴보세요.

PostgreSQL 버전 18에서는 [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) 및 [https://www.postgresql.org/docs/current/pgstatstatements.html](https://www.postgresql.org/docs/current/pgstatstatements.html)의 새 열을 사용하여 병렬 작업자 활동을 모니터링할 수 있습니다.
+ `parallel_workers_to_launch`: 시작될 계획인 병렬 작업자 수
+ `parallel_workers_launched`: 실제로 시작된 병렬 작업자 수

이러한 지표는 계획된 병렬 처리와 실제 병렬 처리 간의 불일치를 식별하는 데 도움이 되며, 이는 리소스 제약 또는 구성 문제를 나타낼 수 있습니다. 다음 쿼리를 사용하여 병렬 실행을 모니터링합니다.

데이터베이스 수준 병렬 작업자 지표의 경우:

```
SELECT datname, parallel_workers_to_launch, parallel_workers_launched
FROM pg_stat_database
WHERE datname = current_database();
```

쿼리 수준 병렬 작업자 지표의 경우:

```
SELECT query, parallel_workers_to_launch, parallel_workers_launched
FROM pg_stat_statements
ORDER BY parallel_workers_launched;
```

## 병렬 처리를 제어하는 방법
<a name="PostgreSQL.ParallelQueries.ControlParallelism"></a>

쿼리 병렬 처리를 제어하는 방법에는 여러 가지가 있으며, 각 방법은 다양한 시나리오와 요구 사항에 맞게 설계되었습니다.

전역적으로 자동 병렬 처리를 비활성화하려면 [. 파라미터 그룹을 수정](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithParamGroups.Modifying.html)하여 설정합니다.

```
max_parallel_workers_per_gather = 0;
```

영구 사용자별 설정의 경우 ALTER ROLE 명령은 특정 사용자의 향후 모든 세션에 적용되는 파라미터를 설정하는 방법을 제공합니다.

예제:

`ALTER ROLE username SET max_parallel_workers_per_gather = 4;`는 이 사용자가 데이터베이스에 연결할 때마다 필요한 경우 세션에서 이 병렬 작업자 설정을 사용하도록 합니다.

세션 수준 제어는 현재 데이터베이스 세션 기간 동안 파라미터를 수정하는 SET 명령을 사용하여 수행할 수 있습니다. 이는 다른 사용자나 향후 세션에 영향을 주지 않고 설정을 일시적으로 조정해야 할 때 특히 유용합니다. 일단 설정되면 이러한 파라미터는 명시적으로 재설정되거나 세션이 종료될 때까지 유효합니다. 명령은 간단합니다.

```
SET max_parallel_workers_per_gather = 4;
-- Run your queries
RESET max_parallel_workers_per_gather;
```

보다 세분화된 제어를 위해 SET LOCAL을 사용하면 단일 트랜잭션에 대한 파라미터를 수정할 수 있습니다. 이는 트랜잭션 내의 특정 쿼리 세트에 대한 설정을 조정해야 할 때 이상적이며, 그 이후에는 설정이 자동으로 이전 값으로 되돌아갑니다. 이 접근 방식은 동일한 세션 내의 다른 작업에 의도하지 않은 영향을 방지하는 데 도움이 됩니다.

## 병렬 쿼리 동작 진단
<a name="PostgreSQL.ParallelQueries.Diagnosing"></a>

`EXPLAIN (ANALYZE, VERBOSE)`를 사용하여 쿼리가 병렬 실행을 사용했는지 확인합니다.
+ `Gather`, `Gather Merge` 또는 `Parallel Seq Scan`과 같은 노드를 찾습니다.
+ 병렬 처리가 있는 계획과 없는 계획을 비교합니다.

비교를 위해 병렬 처리를 일시적으로 비활성화하려면: 다음을 수행합니다.

```
SET max_parallel_workers_per_gather = 0;
EXPLAIN ANALYZE <your_query>;
RESET max_parallel_workers_per_gather;
```

# RDS for PostgreSQL DB 인스턴스에 파라미터로 작업
<a name="Appendix.PostgreSQL.CommonDBATasks.Parameters"></a>

일부 경우, 사용자 정의 파라미터 그룹을 지정하지 않고 RDS for PostgreSQL DB 인스턴스를 생성할 수 있습니다. 이 경우 선택한 PostgreSQL 버전에 대한 기본 파라미터 그룹을 사용하여 DB 인스턴스가 생성됩니다. 예를 들어, PostgreSQL 13.3을 사용하여 RDS for PostgreSQL DB 인스턴스를 생성한다고 가정해 보겠습니다. 이 경우 DB 인스턴스는 PostgreSQL 13 릴리스용 파라미터 그룹(`default.postgres13`)의 값을 사용하여 생성됩니다.

사용자 지정 DB 파라미터 그룹을 생성할 수도 있습니다. RDS for PostgreSQL DB 인스턴스용 설정을 기본값에서 수정하려면 이 작업을 수행해야 합니다. 자세한 방법은 [Amazon RDS의 파라미터 그룹](USER_WorkingWithParamGroups.md)을 참조하세요.

RDS for PostgreSQL DB 인스턴스에서 설정을 여러 가지 방법으로 추적할 수 있습니다. AWS Management Console, AWS CLI 또는 Amazon RDS API를 사용할 수 있습니다. 다음과 같이 인스턴스의 PostgreSQL `pg_settings` 테이블에서 값을 쿼리할 수도 있습니다.

```
SELECT name, setting, boot_val, reset_val, unit
 FROM pg_settings
 ORDER BY name;
```

이 쿼리에서 반환된 값에 대한 자세한 내용은 PostgreSQL 설명서의 [https://www.postgresql.org/docs/current/view-pg-settings.html](https://www.postgresql.org/docs/current/view-pg-settings.html) 섹션을 참조하세요.

RDS for PostgreSQL DB 인스턴스에서 `max_connections` 및 `shared_buffers`에 대한 설정을 변경할 때 특히 주의해야 합니다. 예를 들어 `max_connections` 또는 `shared_buffers`에 대한 설정을 수정해서 실제 워크로드에 비해 너무 높은 값을 사용한다고 가정하겠습니다. 이 경우 RDS for PostgreSQL DB 인스턴스는 시작되지 않습니다. 이 경우 `postgres.log`에 다음과 같은 오류가 기록됩니다.

```
2018-09-18 21:13:15 UTC::@:[8097]:FATAL:  could not map anonymous shared memory: Cannot allocate memory
2018-09-18 21:13:15 UTC::@:[8097]:HINT:  This error usually means that PostgreSQL's request for a shared memory segment
exceeded available memory or swap space. To reduce the request size (currently 3514134274048 bytes), reduce 
PostgreSQL's shared memory usage, perhaps by reducing shared_buffers or max_connections.
```

그러나 PostgreSQL DB 파라미터 그룹의 기본 RDS에 포함된 설정 값은 변경할 수 없습니다. 파라미터에 대한 설정을 변경하려면 먼저 사용자 지정 DB 파라미터 그룹을 생성합니다. 그런 다음 해당 사용자 정의 그룹의 설정을 변경한 다음 사용자 정의 파라미터 그룹을 RDS for PostgreSQL DB 인스턴스에 적용합니다. 자세한 내용은 [Amazon RDS의 파라미터 그룹](USER_WorkingWithParamGroups.md)를 참조하세요.

RDS for PostgreSQL에는 두 가지 유형의 파라미터가 있습니다.
+ **정적 파라미터** - 정적 파라미터를 사용하려면 변경 후 RDS for PostgreSQL DB 인스턴스를 재부팅해야 새 값이 적용됩니다.
+ **동적 파라미터** - 동적 파라미터는 설정을 변경한 후 재부팅할 필요가 없습니다.

**참고**  
RDS for PostgreSQL DB 인스턴스가 자체 사용자 정의 DB 파라미터 그룹을 사용하는 경우, 실행 중인 DB 인스턴스에서 동적 파라미터 값을 변경할 수 있습니다. AWS Management Console, AWS CLI 또는 Amazon RDS API를 사용하여 이 작업을 수행할 수 있습니다.

권한이 있는 경우 `ALTER DATABASE`, `ALTER ROLE` 및 `SET` 명령을 사용하여 파라미터 값을 변경할 수도 있습니다.

## RDS for PostgreSQL DB 인스턴스 파라미터 목록
<a name="Appendix.PostgreSQL.CommonDBATasks.Parameters.parameters-list"></a>

다음 표에는 RDS for PostgreSQL DB 인스턴스에서 사용할 수 있는 일부 파라미터가 나와 있습니다. 사용 가능한 모든 파라미터를 보려면 [describe-db-parameters](https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-parameters.html) AWS CLI 명령을 사용하세요. 예를 들어 RDS for PostgreSQL 버전 13의 기본 파라미터 그룹에서 사용할 수 있는 모든 파라미터 목록을 가져오려면 다음을 실행합니다.

```
aws rds describe-db-parameters --db-parameter-group-name default.postgres13
```

콘솔을 사용할 수도 있습니다. Amazon RDS 메뉴에서 **파라미터 그룹**을 선택한 다음 AWS 리전에서 사용 가능한 파라미터 그룹 중에서 파라미터 그룹을 선택합니다.


|  파라미터 이름  |  적용 유형  |  설명  | 
| --- | --- | --- | 
|  `application_name`  | 동적 | 애플리케이션 이름이 통계 및 로그에 표시되도록 설정합니다. | 
|  `archive_command`  | 동적 | WAL 파일을 보관하기 위해 호출할 셸 명령을 설정합니다. | 
|  `array_nulls`  | 동적 | 어레이의 NULL 요소 입력을 활성화합니다. | 
|  `authentication_timeout`  | 동적 | 클라이언트 인증 완료를 위한 최대 허용 시간을 설정합니다. | 
|  `autovacuum`  | 동적 | autovacuum 서브프로세스를 시작합니다. | 
|  `autovacuum_analyze_scale_factor`  | 동적 | 분석 전 삽입, 업데이트 또는 삭제되는 튜플 수를 reltuples 분수 값으로 지정합니다. | 
|  `autovacuum_analyze_threshold`  | 동적 | 분석 전 삽입, 업데이트 또는 삭제되는 튜플의 최소 수를 지정합니다. | 
|  `autovacuum_freeze_max_age`  | 정적 | 트랜잭션 ID 랩어라운드를 방지하기 위한 테이블의 autovacuum 기간을 지정합니다. | 
|  `autovacuum_naptime`  | 동적 | autovacuum 실행 간 절전 시간을 지정합니다. | 
|  `autovacuum_max_workers`  | 정적 | autovacuum 작업자 프로세스를 동시에 실행할 수 있는 최대 수를 설정합니다. | 
|  `autovacuum_vacuum_cost_delay`  | 동적 | autovacuum에서 vacuum 코스트 지연 시간(밀리초)을 지정합니다. | 
|  `autovacuum_vacuum_cost_limit`  | 동적 | autovacuum에서 지연 시간 이전에 이용 가능한 vacuum 코스트 값을 지정합니다. | 
|  `autovacuum_vacuum_scale_factor`  | 동적 | vacuum 전 업데이트 또는 삭제되는 튜플 수를 reltuples 분수 값으로 지정합니다. | 
|  `autovacuum_vacuum_threshold`  | 동적 | vacuum 전 업데이트 또는 삭제되는 튜플의 최소 수를 지정합니다. | 
|  `backslash_quote`  | 동적 | 문자열 리터럴에서 백슬래시(\$1)의 허용 여부를 설정합니다. | 
|  `bgwriter_delay`  | 동적 | 라운드 사이에 백그라운드 라이터의 절전 시간을 지정합니다. | 
|  `bgwriter_lru_maxpages`  | 동적 | 백그라운드 라이터가 라운드마다 LRU 페이지를 작성할 최대 수를 지정합니다. | 
|  `bgwriter_lru_multiplier`  | 동적 | 라운드마다 해제할 평균 버퍼 사용량의 배수를 지정합니다. | 
|  `bytea_output`  | 동적 | 바이트의 출력 형식을 설정합니다. | 
|  `check_function_bodies`  | 동적 | CREATE FUNCTION 도중 함수 본문을 검사합니다. | 
|  `checkpoint_completion_target`  | 동적 | 체크포인트 도중 변경된 버퍼 플러시에 사용된 시간으로 체크포인트 간격의 분수 값입니다. | 
|  `checkpoint_segments`  | 동적 | 로그 세그먼트에서 자동 write-ahead log(WAL) 체크포인트의 최대 간격을 설정합니다. | 
|  `checkpoint_timeout`  | 동적 | 자동 WAL 체크포인트 사이의 최대 시간을 설정합니다. | 
|  `checkpoint_warning`  | 동적 | 체크포인트 세그먼트가 이 파라미터 값보다 더 빨리 채워지는 경우 경고를 활성화합니다. | 
|  `client_connection_check_interval`  | 동적 |  쿼리를 실행하는 동안 연결 끊김 검사 사이의 시간 간격을 설정합니다. | 
|  `client_encoding`  | 동적 | 클라이언트 문자 세트 인코딩을 설정합니다. | 
|  `client_min_messages`  | 동적 | 클라이언트에게 보여지는 메시지 수준을 설정합니다. | 
|  `commit_delay`  | 동적 | 트랜잭션 커밋부터 디스크에 대한 WAL 플러시까지 지연 시간(밀리초)을 설정합니다. | 
|  `commit_siblings`  | 동적 | commit\$1delay 실행 전에 동시에 열려 있는 트랜잭션 최소 개수를 설정합니다. | 
|  `constraint_exclusion`  | 동적 | planner가 제약 조건을 사용하여 쿼리를 최적화하도록 활성화합니다. | 
|  `cpu_index_tuple_cost`  | 동적 | 인덱스 스캔 중 각 인덱스 항목을 처리하는 데 따른 planner의 예상 코스트를 설정합니다. | 
|  `cpu_operator_cost`  | 동적 | 각 연산자 또는 함수 호출을 처리하는 데 따른 planner의 예상 코스트를 설정합니다. | 
|  `cpu_tuple_cost`  | 동적 | 각 튜플(행)을 처리하는 데 따른 planner의 예상 코스트를 설정합니다. | 
|  `cursor_tuple_fraction`  | 동적 | planner가 예상하는 검색할 커서 행의 분수 값을 설정합니다. | 
|  `datestyle`  | 동적 | 날짜와 시간 값에 대한 표시 형식을 설정합니다. | 
|  `deadlock_timeout`  | 동적 | 교착 상태 여부를 확인하기 이전 잠금 대기 시간을 설정합니다. | 
|  `debug_pretty_print`  | 동적 | 구문과 실행 계획 트리를 들여쓰기 하여 표시합니다. | 
|  `debug_print_parse`  | 동적 | 각 쿼리의 구문 분석 트리를 기록합니다. | 
|  `debug_print_plan`  | 동적 | 각 쿼리의 실행 계획을 기록합니다. | 
|  `debug_print_rewritten`  | 동적 | 각 쿼리에서 재작성된 구문 분석 트리를 기록합니다. | 
|  `default_statistics_target`  | 동적 | 기본 통계 대상을 설정합니다. | 
|  `default_tablespace`  | 동적 | 테이블과 인덱스를 생성할 기본 테이블스페이스를 설정합니다. | 
|  `default_transaction_deferrable`  | 동적 | 새로운 트랜잭션의 기본 deferrable 상태를 설정합니다. | 
|  `default_transaction_isolation`  | 동적 | 새로운 트랜잭션마다 트랜잭션 격리 수준을 설정합니다. | 
|  `default_transaction_read_only`  | 동적 | 새로운 트랜잭션의 기본 읽기 전용 상태를 설정합니다. | 
|  `default_with_oids`  | 동적 | 새로운 테이블을 생성할 때 객체 ID(OID)가 기본적으로 포함됩니다. | 
|  `effective_cache_size`  | 동적 | 디스크 캐시 크기에 대한 planner의 가정을 설정합니다. | 
|  `effective_io_concurrency`  | 동적 | 디스크 하위 시스템에서 효율적으로 동시에 처리할 수 있는 요청 수를 지정합니다. | 
|  `enable_bitmapscan`  | 동적 | planner가 비트맵 스캔 계획을 사용할 수 있도록 활성화합니다. | 
|  `enable_hashagg`  | 동적 | planner가 해시된 집계 계획을 사용할 수 있도록 활성화합니다. | 
|  `enable_hashjoin`  | 동적 | planner가 해시 조인 계획을 사용할 수 있도록 활성화합니다. | 
|  `enable_indexscan`  | 동적 | planner가 인덱스 스캔 계획을 사용할 수 있도록 활성화합니다. | 
|  `enable_material`  | 동적 | planner가 구체화를 사용할 수 있도록 활성화합니다. | 
|  `enable_mergejoin`  | 동적 | planner가 병합 조인 계획을 사용할 수 있도록 활성화합니다. | 
|  `enable_nestloop`  | 동적 | planner가 중첩 루프 조인 계획을 사용할 수 있도록 활성화합니다. | 
|  `enable_seqscan`  | 동적 | planner가 순차적 스캔 계획을 사용할 수 있도록 활성화합니다. | 
|  `enable_sort`  | 동적 | planner가 명시적 정렬 단계를 사용할 수 있도록 활성화합니다. | 
|  `enable_tidscan`  | 동적 | planner가 TID 스캔 계획을 사용할 수 있도록 활성화합니다. | 
|  `escape_string_warning`  | 동적 | 일반 문자열 리터럴의 백슬래시(\$1) 이스케이프에 대해 경고합니다. | 
|  `extra_float_digits`  | 동적 | 부동 소수점으로 표시할 자릿수를 설정합니다. | 
|  `from_collapse_limit`  | 동적 | 서브 쿼리가 축소되지 않는 FROM 목록 크기를 설정합니다. | 
|  `fsync`  | 동적 | 업데이트를 디스크와 강제로 동기화합니다. | 
|  `full_page_writes`  | 동적 | 체크포인트 후 최초 변경 시 전체 페이지를 WAL에 기입합니다. | 
|  `geqo`  | 동적 | 유전적 쿼리 최적화를 활성화합니다. | 
|  `geqo_effort`  | 동적 | GEQO: 다른 GEQO 파라미터의 기본값을 설정하는 데 사용됩니다. | 
|  `geqo_generations`  | 동적 | GEQO: 알고리즘의 반복 횟수입니다. | 
|  `geqo_pool_size`  | 동적 | GEQO: 모집단의 개체 수입니다. | 
|  `geqo_seed`  | 동적 | GEQO: 무작위 경로 선택을 위한 시드(seed)를 지정합니다. | 
|  `geqo_selection_bias`  | 동적 | GEQO: 모집단 내 선택적 압력을 지정합니다. | 
|  `geqo_threshold`  | 동적 | GEQO가 사용되는 FROM 항목의 임계값을 설정합니다. | 
|  `gin_fuzzy_search_limit`  | 동적 | 정확한 GIN 기준 검색에 허용되는 최대 결과 수를 설정합니다. | 
|  `hot_standby_feedback`  | 동적 | 핫 스탠바이가 피드백 메시지를 기본 또는 업스트림 스탠바이로 전송하는지 여부를 결정합니다. | 
|  `intervalstyle`  | 동적 | 간격 값에 대한 표시 형식을 설정합니다. | 
|  `join_collapse_limit`  | 동적 | JOIN 구문이 결합되지 않는 FROM 목록 크기를 설정합니다. | 
|  `lc_messages`  | 동적 | 메시지 표시 언어를 설정합니다. | 
|  `lc_monetary`  | 동적 | 통화 금액의 형식으로 사용할 로캘을 설정합니다. | 
|  `lc_numeric`  | 동적 | 숫자의 형식으로 사용할 로캘을 설정합니다. | 
|  `lc_time`  | 동적 | 날짜와 시간 값의 형식으로 사용할 로캘을 설정합니다. | 
|  `log_autovacuum_min_duration`  | 동적 | autovacuum 작업이 기록되는 최소 실행 시간을 설정합니다. | 
|  `log_checkpoints`  | 동적 | 각 체크포인트를 기록합니다. | 
|  `log_connections`  | 동적 | 성공한 연결을 모두 기록합니다. | 
|  `log_disconnections`  | 동적 | 지속 시간을 포함해 세션 종료를 기록합니다. | 
|  `log_duration`  | 동적 | 완료된 개별 SQL 문의 지속 시간을 기록합니다. | 
|  `log_error_verbosity`  | 동적 | 기록된 메시지의 세부 사항을 설정합니다. | 
|  `log_executor_stats`  | 동적 | 실행기 성능 통계를 서버 로그에 기록합니다. | 
|  `log_filename`  | 동적 | 로그 파일의 이름 패턴을 설정합니다. | 
|  `log_file_mode`  | 동적 | 로그 파일에 대한 파일 권한을 설정합니다. 기본값은 0644입니다. | 
|  `log_hostname`  | 동적 | 연결 로그에 호스트 이름을 기록합니다. PostgreSQL 12 이상 버전에서는 이 파라미터가 기본적으로 '해제' 상태입니다. 이 파라미터를 켜면 연결은 DNS 역방향 조회를 사용하여 연결 로그에 캡처되는 호스트 이름을 가져옵니다. 이 파라미터를 켰다면, 연결을 설정하는 데 걸리는 시간이 달라지는지 모니터링해야 합니다. | 
|  `log_line_prefix `  | 동적 | 각 로그 행에 접두사가 붙은 정보를 제어합니다. | 
|  `log_lock_waits`  | 동적 | 오랜 잠금 대기 시간을 기록합니다. | 
|  `log_min_duration_statement`  | 동적 | 문이 기록되는 최소 실행 시간을 설정합니다. | 
|  `log_min_error_statement`  | 동적 | 이 수준 이상으로 오류 원인이 되는 모든 문을 기록합니다. | 
|  `log_min_messages`  | 동적 | 기록되는 메시지 수준을 설정합니다. | 
|  `log_parser_stats`  | 동적 | 구문 분석기 성능 통계를 서버 로그에 기록합니다. | 
|  `log_planner_stats`  | 동적 | planner 성능 통계를 서버 로그에 기록합니다. | 
|  `log_rotation_age`  | 동적 | N분 후에 자동 로그 파일 로테이션이 일어납니다. | 
|  `log_rotation_size`  | 동적 | N킬로바이트 후에 자동 로그 파일 로테이션이 일어납니다. | 
|  `log_statement`  | 동적 | 기록할 문 유형을 설정합니다. | 
|  `log_statement_stats`  | 동적 | 누적 성능 통계를 서버 로그에 기록합니다. | 
|  `log_temp_files`  | 동적 | 이 킬로바이트 수치보다 큰 임시 파일의 사용을 기록합니다. | 
|  `log_timezone`  | 동적 | 로그 메시지에 사용할 표준 시간대를 설정합니다. | 
|  `log_truncate_on_rotation`  | 동적 | 로그 순환 중에 동일한 이름의 기존 로그 파일을 잘라냅니다. | 
|  `logging_collector`  | 정적 | 하위 프로세스를 시작하여 stderr 출력 및/또는 csvlog를 로그 파일로 캡처합니다. | 
|  `maintenance_work_mem`  | 동적 | 유지 관리 작업에 사용할 최대 메모리를 설정합니다. | 
|  `max_connections`  | 정적 | 동시에 접속할 수 있는 최대 수를 설정합니다. | 
|  `max_files_per_process`  | 정적 | 서버 프로세스마다 파일을 동시에 열 수 있는 최대 수를 설정합니다. | 
|  `max_locks_per_transaction`  | 정적 | 하나의 트랜잭션에서 사용할 수 있는 최대 잠금 횟수를 설정합니다. | 
|  `max_pred_locks_per_transaction`  | 정적 | 하나의 트랜잭션에서 사용할 수 있는 최대 술어(predicate) 잠금 횟수를 설정합니다. | 
|  `max_prepared_transactions`  | 정적 | 트랜잭션을 동시에 준비할 수 있는 최대 수를 설정합니다. | 
|  `max_stack_depth`  | 동적 | 최대 스택 깊이(KB)를 설정합니다. | 
|  `max_standby_archive_delay`  | 동적 | 핫 스탠바이 서버가 아카이브 WAL 데이터를 처리할 때 쿼리 취소까지 걸리는 최대 지연 시간을 설정합니다. | 
|  `max_standby_streaming_delay`  | 동적 | 핫 스탠바이 서버가 스트리밍 WAL 데이터를 처리할 때 쿼리 취소까지 걸리는 최대 지연 시간을 설정합니다. | 
| max\$1wal\$1size | 동적 | 검사 점을 트리거하는 WAL 크기(MB)를 설정합니다.[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Parameters.html) Amazon RDS for PostgreSQL DB 인스턴스에서 다음 명령을 사용하여 현재 값을 확인합니다. <pre>SHOW max_wal_size;</pre>  | 
| min\$1wal\$1size | 동적 | WAL을 축소할 최소 크기를 설정합니다. PostgreSQL 버전 9.6 이하의 경우 min\$1wal\$1size는 16MB 단위입니다. PostgreSQL 버전 10 이상의 경우 min\$1wal\$1size는 1MB 단위입니다. | 
|  `quote_all_identifiers`  | 동적 | SQL 조각 생성 시 모든 식별자에 인용 부호(")를 추가합니다. | 
|  `random_page_cost`  | 동적 | 비순차적으로 가져온 디스크 페이지에 대한 planner의 예상 코스트를 설정합니다. 이 파라미터는 쿼리 계획 관리(QPM)가 켜져 있지 않으면 값이 없습니다. QPM이 켜져 있으면 이 파라미터의 기본값은 4입니다. | 
| rds.adaptive\$1autovacuum | 동적 | 트랜잭션 ID 임계값이 초과될 때마다 autovacuum 파라미터를 자동으로 조정합니다. | 
| rds.force\$1ssl | 동적 | SSL 연결을 사용해야 합니다. RDS for PostgreSQL 버전 15의 기본값은 1(켜짐)로 설정되어 있습니다. 다른 모든 RDS for PostgreSQL 메이저 버전 14 이상에는 기본값이 0(꺼짐)로 설정되어 있습니다. | 
|  `rds.local_volume_spill_enabled`  | 정적 | 로컬 볼륨에 논리적 유출 파일 쓰기를 활성화합니다. | 
|  `rds.log_retention_period`  | 동적 | Amazon RDS가 n분보다 오래된 PostgreSQL 로그를 삭제하도록 로그 보존을 설정합니다. | 
| rds.rds\$1superuser\$1reserved\$1connections | 정적 | rds\$1superuser용으로 예약된 연결 슬롯 수를 설정합니다. 이 파라미터는 버전 15 이상에서만 사용할 수 있습니다. 자세한 내용은 [reserved\$1connections](https://www.postgresql.org/docs/current/runtime-config-connection.html#GUC-RESERVED-CONNECTIONS) PostgreSQL 설명서를 참조하세요. | 
| `rds.replica_identity_full` | 동적 | 이 파라미터를 `on`으로 설정하면 모든 데이터베이스 테이블에 대해 복제본 ID 설정이 `FULL`로 재정의됩니다. 즉, `REPLICA IDENTITY FULL` 설정에 관계없이 모든 열 값이 Write Ahead Log(WAL)에 기록됩니다.  이 파라미터를 켜면 추가 WAL 로깅으로 인해 데이터베이스 인스턴스 IOPS가 증가할 수 있습니다.   | 
| rds.restrict\$1password\$1commands | 정적 | 암호를 관리할 수 있는 사람을 rds\$1password 역할이 있는 사용자로 제한합니다. 암호 제한을 활성화하려면 이 파라미터를 1로 설정합니다. 기본값은 0입니다. | 
|  `search_path`  | 동적 | 스키마로 한정되지 않은 이름의 스키마 검색 순서를 설정합니다. | 
|  `seq_page_cost`  | 동적 | 순차적으로 가져온 디스크 페이지에 대한 planner의 예상 코스트를 설정합니다. | 
|  `session_replication_role`  | 동적 | 트리거 및 다시 쓰기 규칙에 대한 세션 동작을 설정합니다. | 
|  `shared_buffers`  | 정적 | 서버에서 사용할 공유 메모리 버퍼의 수를 설정합니다. | 
|  `shared_preload_libraries `  | 정적 | RDS for PostgreSQL DB 인스턴스에 미리 로드할 공유 라이브러리를 나열합니다. 지원되는 값으로는 auto\$1explain, orafce, pgaudit, pglogical, pg\$1bigm, pg\$1cron, pg\$1hint\$1plan, pg\$1prewarm, pg\$1similarity, pg\$1stat\$1statements, pg\$1tle, pg\$1transport, plprofiler, plrust가 있습니다. | 
|  `ssl`  | 동적 | SSL 연결을 활성화합니다. | 
|  `sql_inheritance`  | 동적 | 다양한 명령에서 서브테이블이 기본적으로 상속됩니다. | 
|  `ssl_renegotiation_limit`  | 동적 | 암호화 키를 재협상하기 전에 전송 및 수신할 트래픽 양을 설정합니다. | 
|  `standard_conforming_strings`  | 동적 | ... 문자열에서 백슬래시가 리터럴로 처리됩니다. | 
|  `statement_timeout`  | 동적 | 모든 문에 허용되는 최대 지속 시간을 설정합니다. | 
|  `synchronize_seqscans`  | 동적 | 동기 방식의 순차적 스캔을 활성화합니다. | 
|  `synchronous_commit`  | 동적 | 현재 트랜잭션 동기화 수준을 설정합니다. | 
|  `tcp_keepalives_count`  | 동적 | TCP keepalive의 최대 재전송 횟수를 지정합니다. | 
|  `tcp_keepalives_idle`  | 동적 | TCP keepalive의 실행 주기를 지정합니다. | 
|  `tcp_keepalives_interval`  | 동적 | TCP keepalive의 재전송 주기를 지정합니다. | 
|  `temp_buffers`  | 동적 | 각 세션에서 사용하는 임시 버퍼의 최대 수를 설정합니다. | 
| temp\$1file\$1limit | 동적 | 임시 파일이 증가할 수 있는 최대 크기(KB)를 설정합니다. | 
|  `temp_tablespaces`  | 동적 | 임시 테이블 및 정렬 파일에 사용할 테이블스페이스를 설정합니다. | 
|  `timezone`  | 동적 | 타임스탬프를 표시 및 해석할 시간대를 설정합니다. IANA(Internet Assigned Numbers Authority)에서는 [https://www.iana.org/time-zones](https://www.iana.org/time-zones)에서 일 년에 여러 번 새로운 표준 시간대를 게시합니다. RDS에서 PostgreSQL의 새로운 마이너 유지 관리 릴리스를 릴리스할 때마다 릴리스 시점의 최신 표준 시간대 데이터가 함께 제공됩니다. 최신 RDS for PostgreSQL 버전을 사용하면 RDS의 최신 표준 시간대 데이터를 갖게 됩니다. DB 인스턴스에 최신 표준 시간대 데이터가 있는지 확인하려면 상위 DB 엔진 버전으로 업그레이드하는 것이 좋습니다. PostgreSQL DB 인스턴스의 표준 시간대 테이블은 수동으로 수정할 수 없습니다. RDS는 실행 중인 DB 인스턴스의 표준 시간대 데이터를 수정하거나 재설정하지 않습니다. 새 표준 시간대 데이터는 데이터베이스 엔진 버전 업그레이드를 수행할 때만 설치됩니다. | 
|  `track_activities`  | 동적 | 명령 실행에 대한 정보를 수집합니다. | 
|  `track_activity_query_size`  | 정적 | pg\$1stat\$1activity.current\$1query에 예약되는 크기(바이트)를 설정합니다. | 
|  `track_counts`  | 동적 | 데이터베이스 작업에 관한 통계를 수집합니다. | 
|  `track_functions`  | 동적 | 데이터베이스 작업에 관한 함수 수준 통계를 수집합니다. | 
|  `track_io_timing`  | 동적 | 데이터베이스 I/O 작업에 관한 시간 통계를 수집합니다. | 
|  `transaction_deferrable`  | 동적 | 잠재적 직렬화 오류 없이 시작될 때까지 직렬화가 가능한 읽기 전용 트랜잭션의 지연 여부를 결정합니다. | 
|  `transaction_isolation`  | 동적 | 현재 트랜잭션 격리 수준을 설정합니다. | 
|  `transaction_read_only`  | 동적 | 현재 트랜잭션의 읽기 전용 상태를 설정합니다. | 
|  `transform_null_equals`  | 동적 | expr=NULL을 expr IS NULL로 처리합니다. | 
|  `update_process_title`  | 동적 | 프로세스 제목을 업데이트하여 활성 SQL 명령을 표시합니다. | 
|  `vacuum_cost_delay`  | 동적 | vacuum 코스트 지연 시간(밀리초)을 지정합니다. | 
|  `vacuum_cost_limit`  | 동적 | 지연 시간 이전에 이용 가능한 vacuum 코스트 값을 지정합니다. | 
|  `vacuum_cost_page_dirty`  | 동적 | vacuum으로 페이지 변경 시 부과되는 vacuum 코스트를 지정합니다. | 
|  `vacuum_cost_page_hit`  | 동적 | 버퍼 캐시에서 발견되는 페이지에 대한 vacuum 코스트를 지정합니다. | 
|  `vacuum_cost_page_miss`  | 동적 | 버퍼 캐시에서 발견되지 않는 페이지에 대한 vacuum 코스트를 지정합니다. | 
|  `vacuum_defer_cleanup_age`  | 동적 | vacuum 및 hot cleanup을 연기해야 하는 트랜잭션 수를 지정합니다(있는 경우). | 
|  `vacuum_freeze_min_age`  | 동적 | vacuum에서 테이블 행을 동결해야 하는 최소 기간을 지정합니다. | 
|  `vacuum_freeze_table_age`  | 동적 | vacuum에서 전체 테이블을 스캔하여 튜플을 동결해야 하는 기간을 지정합니다. | 
|  `wal_buffers`  | 정적 | WAL 기능을 위해 공유 메모리에서 사용할 디스크 페이지 버퍼 수를 설정합니다. | 
|  `wal_writer_delay`  | 동적 | WAL 플러시 사이에 WAL 작성기의 절전 시간을 지정합니다. | 
|  `work_mem`  | 동적 | 쿼리 작업 공간에 사용할 최대 메모리를 설정합니다. | 
|  `xmlbinary`  | 동적 | XML에서 바이너리 값의 인코딩 방식을 설정합니다. | 
|  `xmloption`  | 동적 | 암시적 구문 분석 및 직렬화 작업에서 XML 데이터를 문서 또는 내용 조각으로 간주할지 여부를 설정합니다. | 

Amazon RDS는 모든 파라미터에서 기본 PostgreSQL 단위를 사용합니다. 다음 표는 각 파라미터의 PostgreSQL 기본 단위를 나타냅니다.


|  파라미터 이름  |  단위  | 
| --- | --- | 
| `archive_timeout` | s | 
| `authentication_timeout` | s | 
| `autovacuum_naptime` | s | 
| `autovacuum_vacuum_cost_delay` | ms | 
| `bgwriter_delay` | ms | 
| `checkpoint_timeout` | s | 
| `checkpoint_warning` | s | 
| `deadlock_timeout` | ms | 
| `effective_cache_size` | 8KB | 
| `lock_timeout` | ms | 
| `log_autovacuum_min_duration` | ms | 
| `log_min_duration_statement` | ms | 
| `log_rotation_age` | 분 | 
| `log_rotation_size` | KB | 
| `log_temp_files` | KB | 
| `maintenance_work_mem` | KB | 
| `max_stack_depth` | KB | 
| `max_standby_archive_delay` | ms | 
| `max_standby_streaming_delay` | ms | 
| `post_auth_delay` | s | 
| `pre_auth_delay` | s | 
| `segment_size` | 8KB | 
| `shared_buffers` | 8KB | 
| `statement_timeout` | ms | 
| `ssl_renegotiation_limit` | KB | 
| `tcp_keepalives_idle` | s | 
| `tcp_keepalives_interval` | s | 
| `temp_file_limit` | KB | 
| `work_mem` | KB | 
| `temp_buffers` | 8KB | 
| `vacuum_cost_delay` | ms | 
| `wal_buffers` | 8KB | 
| `wal_receiver_timeout` | ms | 
| `wal_segment_size` | B | 
| `wal_sender_timeout` | ms | 
| `wal_writer_delay` | ms | 
| `wal_receiver_status_interval` | s | 