> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-3a82795f.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> PostgreSQL 데이터베이스의 테이블을 사용해 ClickHouse 데이터베이스를 생성합니다.

# MaterializedPostgreSQL

export const CloudNotSupportedBadge = () => {
  return <div className="cloudNotSupportedBadge">
            <div className="cloudNotSupportedIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.5" d="M6.33366 12.6666L12.3739 12.6667C13.6593 12.6667 14.7073 11.6187 14.7073 10.3334C14.7073 9.04804 13.6593 8.00003 12.3739 8.00003C12.3739 8.00003 12.3337 7.66659 12.0003 7.33325M10.667 5.33322C8.00033 2.33325 4.45395 4.78537 4.14195 6.68203C2.55728 6.7627 1.29395 8.06203 1.29395 9.6667C1.29395 11.3234 2.66699 12.6666 4.00033 12.6666" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.5" d="M2.66699 14L12.0003 4.66663" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>

        </div>
            Not supported in ClickHouse Cloud
        </div>;
};

export const ExperimentalBadge = () => {
  return <div className="experimentalBadge">
            <div className="experimentalIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.25" d="M5.5 2H10.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M9.50015 2V6.19625L13.4283 12.7425C13.4738 12.8183 13.4985 12.9049 13.4996 12.9934C13.5008 13.0818 13.4785 13.169 13.435 13.246C13.3914 13.323 13.3283 13.3871 13.2519 13.4317C13.1755 13.4764 13.0886 13.4999 13.0002 13.5H3.00015C2.91164 13.5 2.8247 13.4766 2.74822 13.432C2.67174 13.3874 2.60847 13.3233 2.56487 13.2463C2.52126 13.1693 2.49889 13.082 2.50004 12.9935C2.50119 12.905 2.52582 12.8184 2.5714 12.7425L6.50015 6.19625V2" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M4.47656 9.56754C5.30344 9.41254 6.47656 9.47942 7.99969 10.25C10.0153 11.2707 11.4216 11.0569 12.2184 10.7282" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            Experimental feature. <u><a href="/docs/beta-and-experimental-features#experimental-features">Learn more.</a></u>
        </div>;
};

<Note>
  ClickHouse Cloud 사용자는 PostgreSQL을 ClickHouse로 복제할 때 [ClickPipes](/ko/integrations/clickpipes/home)를 사용하는 것이 좋습니다. ClickPipes는 PostgreSQL에 대한 고성능 CDC(Change Data Capture)를 네이티브로 지원합니다.
</Note>

PostgreSQL 데이터베이스의 테이블을 기반으로 ClickHouse 데이터베이스를 생성합니다. 먼저 `MaterializedPostgreSQL` 엔진을 사용하는 데이터베이스가 PostgreSQL 데이터베이스의 스냅샷을 생성하고 필요한 테이블을 로드합니다. 필요한 테이블에는 지정된 데이터베이스의 스키마 하위 집합에 포함된 테이블 하위 집합을 자유롭게 지정할 수 있습니다. 스냅샷과 함께 데이터베이스 엔진은 LSN을 획득하며, 테이블의 초기 덤프가 완료되면 WAL에서 업데이트를 가져오기 시작합니다. 데이터베이스가 생성된 후 PostgreSQL 데이터베이스에 새로 추가된 테이블은 복제 대상에 자동으로 포함되지 않습니다. 이러한 테이블은 `ATTACH TABLE db.table` 쿼리를 사용해 수동으로 추가해야 합니다.

복제는 PostgreSQL 논리적 복제 프로토콜을 통해 구현됩니다. 이 프로토콜은 DDL 복제는 허용하지 않지만, 복제를 중단시키는 변경이 발생했는지는 확인할 수 있습니다(컬럼 유형 변경, 컬럼 추가/삭제). 이러한 변경이 감지되면 해당 테이블은 업데이트 수신을 중지합니다. 이 경우 `ATTACH`/ `DETACH PERMANENTLY` 쿼리를 사용해 테이블 전체를 다시 로드해야 합니다. DDL이 복제를 중단시키지 않는 경우에는(예: 컬럼 이름 변경) 테이블은 계속 업데이트를 수신합니다(삽입은 위치 기준으로 수행됨).

<Note>
  이 데이터베이스 엔진은 Experimental 상태입니다. 사용하려면 설정 파일에서 `allow_experimental_database_materialized_postgresql`을 1로 설정하거나 `SET` 명령을 사용하십시오:

  ```sql theme={null}
  SET allow_experimental_database_materialized_postgresql=1
  ```
</Note>

<div id="creating-a-database">
  ## 데이터베이스 생성
</div>

```sql theme={null}
CREATE DATABASE [IF NOT EXISTS] db_name [ON CLUSTER cluster]
ENGINE = MaterializedPostgreSQL('host:port', 'database', 'user', 'password') [SETTINGS ...]
```

**엔진 매개변수**

* `host:port` — PostgreSQL 서버 엔드포인트.
* `database` — PostgreSQL 데이터베이스 이름.
* `user` — PostgreSQL 사용자 이름.
* `password` — 사용자 비밀번호.

<div id="example-of-use">
  ## 사용 예시
</div>

```sql theme={null}
CREATE DATABASE postgres_db
ENGINE = MaterializedPostgreSQL('postgres1:5432', 'postgres_database', 'postgres_user', 'postgres_password');

SHOW TABLES FROM postgres_db;

┌─name───┐
│ table1 │
└────────┘

SELECT * FROM postgresql_db.postgres_table;
```

<div id="dynamically-adding-table-to-replication">
  ## 복제에 새 테이블 동적으로 추가하기
</div>

`MaterializedPostgreSQL` 데이터베이스를 생성한 후에는 연결된 PostgreSQL 데이터베이스의 새 테이블이 자동으로 감지되지 않습니다. 이러한 테이블은 수동으로 추가할 수 있습니다:

```sql theme={null}
ATTACH TABLE postgres_database.new_table;
```

<Warning>
  버전 22.1 이전에는 테이블을 복제에 추가할 때 삭제되지 않는 임시 replication slot(이름: `{db_name}_ch_replication_slot_tmp`)이 남았습니다. 22.1 이전 버전의 ClickHouse에서 테이블을 ATTACH하는 경우 이 슬롯을 수동으로 삭제해야 합니다(`SELECT pg_drop_replication_slot('{db_name}_ch_replication_slot_tmp')`). 그렇지 않으면 디스크 사용량이 증가합니다. 이 문제는 22.1에서 수정되었습니다.
</Warning>

<div id="dynamically-removing-table-from-replication">
  ## 복제 대상에서 테이블을 동적으로 제거하기
</div>

특정 테이블을 복제 대상에서 제외할 수 있습니다:

```sql theme={null}
DETACH TABLE postgres_database.table_to_remove PERMANENTLY;
```

<div id="schema">
  ## PostgreSQL 스키마
</div>

PostgreSQL [스키마](https://www.postgresql.org/docs/9.1/ddl-schemas.html)는 3가지 방식으로 구성할 수 있습니다(21.12 버전부터 지원).

1. `MaterializedPostgreSQL` 데이터베이스 엔진 1개당 스키마 1개를 사용합니다. 이 경우 `materialized_postgresql_schema` 설정을 사용해야 합니다.
   테이블은 테이블 이름만으로 액세스합니다:

```sql theme={null}
CREATE DATABASE postgres_database
ENGINE = MaterializedPostgreSQL('postgres1:5432', 'postgres_database', 'postgres_user', 'postgres_password')
SETTINGS materialized_postgresql_schema = 'postgres_schema';

SELECT * FROM postgres_database.table1;
```

2. 하나의 `MaterializedPostgreSQL` 데이터베이스 엔진에 대해, 지정된 테이블 집합이 있는 스키마를 여러 개 사용할 수 있습니다. 이 경우 `materialized_postgresql_tables_list` 설정을 사용해야 합니다. 각 테이블은 해당 스키마와 함께 지정됩니다.
   테이블에 액세스할 때는 스키마 이름과 테이블 이름을 함께 사용합니다:

```sql theme={null}
CREATE DATABASE database1
ENGINE = MaterializedPostgreSQL('postgres1:5432', 'postgres_database', 'postgres_user', 'postgres_password')
SETTINGS materialized_postgresql_tables_list = 'schema1.table1,schema2.table2,schema1.table3',
         materialized_postgresql_tables_list_with_schema = 1;

SELECT * FROM database1.`schema1.table1`;
SELECT * FROM database1.`schema2.table2`;
```

하지만 이 경우 `materialized_postgresql_tables_list`의 모든 테이블은 스키마 이름을 포함해 작성해야 합니다.
`materialized_postgresql_tables_list_with_schema = 1`이 필요합니다.

경고: 이 경우 테이블 이름에 점(.)을 사용할 수 없습니다.

3. 하나의 `MaterializedPostgreSQL` 데이터베이스 엔진에 대해 전체 테이블 집합을 포함하는 여러 스키마를 사용할 수 있습니다. 이 경우 설정 `materialized_postgresql_schema_list`를 사용해야 합니다.

```sql theme={null}
CREATE DATABASE database1
ENGINE = MaterializedPostgreSQL('postgres1:5432', 'postgres_database', 'postgres_user', 'postgres_password')
SETTINGS materialized_postgresql_schema_list = 'schema1,schema2,schema3';

SELECT * FROM database1.`schema1.table1`;
SELECT * FROM database1.`schema1.table2`;
SELECT * FROM database1.`schema2.table2`;
```

경고: 이 경우 테이블 이름에 점(.)은 사용할 수 없습니다.

<div id="requirements">
  ## 요구 사항
</div>

1. PostgreSQL 구성 파일에서 [wal\_level](https://www.postgresql.org/docs/current/runtime-config-wal.html) 설정 값은 `logical`이어야 하며, `max_replication_slots` 매개변수 값은 최소 `2`여야 합니다.

2. 각 복제된 테이블(Replicated Table)에는 다음 [레플리카 아이덴티티](https://www.postgresql.org/docs/10/sql-altertable.html#SQL-CREATETABLE-REPLICA-IDENTITY) 중 하나가 설정되어 있어야 합니다.

* 기본 키(primary key) (기본값)

* 인덱스

```bash theme={null}
postgres# CREATE TABLE postgres_table (a Integer NOT NULL, b Integer, c Integer NOT NULL, d Integer, e Integer NOT NULL);
postgres# CREATE unique INDEX postgres_table_index on postgres_table(a, c, e);
postgres# ALTER TABLE postgres_table REPLICA IDENTITY USING INDEX postgres_table_index;
```

기본 키(primary key)가 항상 가장 먼저 확인됩니다. 기본 키가 없으면 레플리카 아이덴티티 인덱스로 정의된 인덱스를 확인합니다.
인덱스를 레플리카 아이덴티티로 사용하는 경우, 테이블에는 해당 인덱스가 하나만 있어야 합니다.
다음 명령으로 특정 테이블에 어떤 유형이 사용되는지 확인할 수 있습니다.

```bash theme={null}
postgres# SELECT CASE relreplident
          WHEN 'd' THEN 'default'
          WHEN 'n' THEN 'nothing'
          WHEN 'f' THEN 'full'
          WHEN 'i' THEN 'index'
       END AS replica_identity
FROM pg_class
WHERE oid = 'postgres_table'::regclass;
```

<Note>
  [**TOAST**](https://www.postgresql.org/docs/9.5/storage-toast.html) 값의 복제는 지원되지 않습니다. 대신 해당 데이터 타입의 기본값이 사용됩니다.
</Note>

<div id="settings">
  ## 설정
</div>

<div id="materialized-postgresql-tables-list">
  ### `materialized_postgresql_tables_list`
</div>

[MaterializedPostgreSQL](/ko/reference/engines/database-engines/materialized-postgresql) 데이터베이스 엔진을 통해 복제할 PostgreSQL 데이터베이스 테이블 목록을 쉼표로 구분해 설정합니다.

각 테이블에는 대괄호 안에 복제할 컬럼의 일부를 지정할 수 있습니다. 컬럼 일부를 지정하지 않으면 해당 테이블의 모든 컬럼이 복제됩니다.

```sql theme={null}
    materialized_postgresql_tables_list = 'table1(co1, col2),table2,table3(co3, col5, col7)
```

기본값: 빈 목록 — PostgreSQL 데이터베이스 전체가 복제된다는 뜻입니다.

<div id="materialized-postgresql-schema">
  ### `materialized_postgresql_schema`
</div>

기본값: 빈 문자열입니다. (기본 스키마가 사용됩니다)

<div id="materialized-postgresql-schema-list">
  ### `materialized_postgresql_schema_list`
</div>

기본값: 빈 목록입니다. (기본 스키마(schema)가 사용됩니다)

<div id="materialized-postgresql-max-block-size">
  ### `materialized_postgresql_max_block_size`
</div>

데이터를 PostgreSQL 데이터베이스 테이블에 플러시하기 전에 메모리에 수집하는 행 수를 설정합니다.

가능한 값:

* 양의 정수.

기본값: `65536`.

<div id="materialized-postgresql-replication-slot">
  ### `materialized_postgresql_replication_slot`
</div>

사용자가 생성한 replication slot입니다. `materialized_postgresql_snapshot`과 함께 사용해야 합니다.

<div id="materialized-postgresql-snapshot">
  ### `materialized_postgresql_snapshot`
</div>

[PostgreSQL 테이블의 초기 덤프](/ko/reference/engines/database-engines/materialized-postgresql)를 수행할 스냅샷을 식별하는 텍스트 문자열입니다. 반드시 `materialized_postgresql_replication_slot`과 함께 사용해야 합니다.

```sql theme={null}
    CREATE DATABASE database1
    ENGINE = MaterializedPostgreSQL('postgres1:5432', 'postgres_database', 'postgres_user', 'postgres_password')
    SETTINGS materialized_postgresql_tables_list = 'table1,table2,table3';

    SELECT * FROM database1.table1;
```

필요한 경우 DDL 쿼리를 사용해 설정을 변경할 수 있습니다. 다만 `materialized_postgresql_tables_list` 설정은 변경할 수 없습니다. 이 설정의 테이블 목록을 업데이트하려면 `ATTACH TABLE` 쿼리를 사용하십시오.

```sql theme={null}
    ALTER DATABASE postgres_database MODIFY SETTING materialized_postgresql_max_block_size = <new_size>;
```

<div id="materialized_postgresql_use_unique_replication_consumer_identifier">
  ### `materialized_postgresql_use_unique_replication_consumer_identifier`
</div>

복제에 고유한 consumer 식별자를 사용합니다. 기본값: `0`입니다.
`1`로 설정하면 동일한 `PostgreSQL` 테이블을 가리키는 여러 `MaterializedPostgreSQL` 테이블을 설정할 수 있습니다.

<div id="notes">
  ## 참고
</div>

<div id="logical-replication-slot-failover">
  ### 논리적 replication slot의 장애 조치
</div>

프라이머리에 있는 논리적 replication slot은 대기 인스턴스 레플리카에서는 사용할 수 없습니다.
따라서 장애 조치가 발생하면 새 프라이머리(이전의 물리적 대기 인스턴스)는 이전 프라이머리에 있던 슬롯을 전혀 알지 못합니다. 그 결과 PostgreSQL 복제가 중단됩니다.
이를 해결하려면 replication slot을 직접 관리하고 영구적인 replication slot을 정의해야 합니다(관련 정보는 [여기](https://patroni.readthedocs.io/en/latest/SETTINGS.html)에서 확인할 수 있습니다). 슬롯 이름은 `materialized_postgresql_replication_slot` 설정으로 전달해야 하며, `EXPORT SNAPSHOT` 옵션으로 내보내야 합니다. 스냅샷 식별자는 `materialized_postgresql_snapshot` 설정으로 전달해야 합니다.

이 기능은 실제로 필요한 경우에만 사용해야 한다는 점에 유의하십시오. 이를 꼭 사용해야 할 실질적인 이유가 없거나 그 이유를 충분히 이해하지 못한 경우에는 테이블 엔진이 자체 replication slot을 생성하고 관리하도록 두는 편이 더 낫습니다.

**예시([@bchrobot](https://github.com/bchrobot) 제공)**

1. PostgreSQL에서 replication slot을 구성합니다.

   ```yaml theme={null}
   apiVersion: "acid.zalan.do/v1"
   kind: postgresql
   metadata:
     name: acid-demo-cluster
   spec:
     numberOfInstances: 2
     postgresql:
       parameters:
         wal_level: logical
     patroni:
       slots:
         clickhouse_sync:
           type: logical
           database: demodb
           plugin: pgoutput
   ```

2. replication slot이 준비될 때까지 기다린 다음 트랜잭션을 시작하고, 트랜잭션 스냅샷 식별자를 내보냅니다.

   ```sql theme={null}
   BEGIN;
   SELECT pg_export_snapshot();
   ```

3. ClickHouse에서 데이터베이스를 생성합니다.

   ```sql theme={null}
   CREATE DATABASE demodb
   ENGINE = MaterializedPostgreSQL('postgres1:5432', 'postgres_database', 'postgres_user', 'postgres_password')
   SETTINGS
     materialized_postgresql_replication_slot = 'clickhouse_sync',
     materialized_postgresql_snapshot = '0000000A-0000023F-3',
     materialized_postgresql_tables_list = 'table1,table2,table3';
   ```

4. ClickHouse DB로의 복제가 확인되면 PostgreSQL 트랜잭션을 종료합니다. 장애 조치 후에도 복제가 계속되는지 확인합니다.

   ```bash theme={null}
   kubectl exec acid-demo-cluster-0 -c postgres -- su postgres -c 'patronictl failover --candidate acid-demo-cluster-1 --force'
   ```

<div id="required-permissions">
  ### 필요한 권한
</div>

1. [CREATE PUBLICATION](https://postgrespro.ru/docs/postgresql/14/sql-createpublication) -- 쿼리 생성 권한.

2. [CREATE\_REPLICATION\_SLOT](https://postgrespro.ru/docs/postgrespro/10/protocol-replication#PROTOCOL-REPLICATION-CREATE-SLOT) -- 복제 권한.

3. [pg\_drop\_replication\_slot](https://postgrespro.ru/docs/postgrespro/9.5/functions-admin#functions-replication) -- 복제 권한 또는 superuser 권한.

4. [DROP PUBLICATION](https://postgrespro.ru/docs/postgresql/10/sql-droppublication) -- publication의 소유자(MaterializedPostgreSQL engine 자체의 `username`).

`2` 및 `3` 명령을 실행하지 않고 해당 권한 없이도 진행할 수 있습니다. `materialized_postgresql_replication_slot` 및 `materialized_postgresql_snapshot` 설정을 사용하십시오. 단, 매우 주의해서 사용해야 합니다.

테이블 액세스:

1. pg\_publication

2. pg\_replication\_slots

3. pg\_publication\_tables
