> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Managed Postgres 빠른 시작

> NVMe 기반 Postgres 성능을 경험하고 네이티브 ClickHouse 통합으로 실시간 분석을 추가해 보세요

이 페이지에서는 [ClickHouse CLI](/docs/ko/products/cloud/features/cli) (`clickhousectl`)와 `psql`을 사용해 명령줄에서 ClickHouse Managed Postgres를 Provisioning하고, 데이터를 적재하고, 이를 ClickHouse로 복제한 뒤 쿼리하는 방법을 설명합니다. 모든 명령은 비대화형이며, `clickhousectl`은 `--json` 옵션을 사용하면 JSON을 출력합니다.

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

ClickHouse CLI를 설치합니다:

```bash theme={null}
curl https://clickhouse.com/cli | sh
```

`psql`(PostgreSQL 클라이언트 도구, macOS에서는 `brew install libpq`)와 `jq`도 필요합니다.

쓰기 작업(생성, 삭제)에는 [API Key 인증](/docs/ko/products/cloud/features/admin-features/api/openapi)이 필요하고, OAuth 로그인은 읽기 전용입니다:

```bash theme={null}
clickhousectl cloud auth login --api-key <YOUR_KEY> --api-secret <YOUR_SECRET>
```

또는 `CLICKHOUSE_CLOUD_API_KEY` 및 `CLICKHOUSE_CLOUD_API_SECRET` 환경 변수를 설정하십시오. `clickhousectl cloud auth status`로 확인했을 때 범위가 `read/write`인 항목이 표시되어야 합니다.

<div id="part-1-create-and-load">
  ## Part 1: Postgres 생성 및 데이터 적재
</div>

<div id="create-postgres-service">
  ### Postgres 서비스 생성
</div>

서비스를 생성한 후 응답을 저장하십시오. 비밀번호는 한 번만 표시됩니다:

```bash theme={null}
clickhousectl cloud postgres create \
  --name quickstart-pg \
  --region us-east-1 \
  --size c6gd.large \
  --pg-version 18 \
  --json > pg.json
```

응답에는 서비스 ID, 호스트명, 그리고 바로 사용할 수 있는 connection string이 포함됩니다:

```json theme={null}
{
  "id": "3b5a3112-bf02-82d0-bd02-fbe67d5caa7a",
  "name": "quickstart-pg",
  "provider": "aws",
  "region": "us-east-1",
  "postgresVersion": "18",
  "size": "c6gd.large",
  "storageSize": 118,
  "haType": "none",
  "state": "creating",
  "createdAt": "2026-07-22T13:21:22Z",
  "hostname": "quickstart-pg-c1406b50.pg7dd324nz0a1qm1fqskxbjn7m.c0.us-east-1.aws.pg.clickhouse.cloud",
  "username": "postgres",
  "password": "vV6cfEr2p_-TzkCDrZOx",
  "connectionString": "postgres://postgres:vV6cfEr2p_-TzkCDrZOx@quickstart-pg-c1406b50.pg7dd324nz0a1qm1fqskxbjn7m.c0.us-east-1.aws.pg.clickhouse.cloud:5432/postgres?channel_binding=require",
  "isPrimary": true,
  "tags": []
}
```

이 가이드의 나머지 부분에 필요한 정보를 추출합니다:

```bash theme={null}
PG_ID=$(jq -r .id pg.json)
PG_URL=$(jq -r .connectionString pg.json)
```

비밀번호를 분실한 경우 `clickhousectl cloud postgres reset-password $PG_ID --generate` 명령으로 새 비밀번호를 생성하세요.

<div id="wait-for-provisioning">
  ### 서비스 Provisioning이 완료될 때까지 기다리기
</div>

Provisioning에는 몇 분 정도 소요됩니다. 상태가 `running`이 될 때까지 폴링하세요:

```bash theme={null}
while [ "$(clickhousectl cloud postgres get "$PG_ID" --json | jq -r .state)" != "running" ]; do
  sleep 15
done
```

<div id="load-sample-data">
  ### 샘플 데이터 로드
</div>

두 개의 테이블을 생성하고 `psql`을 사용해 이벤트 100만 건을 삽입합니다:

```bash theme={null}
psql "$PG_URL" <<'SQL'
\timing
CREATE TABLE events (
   event_id SERIAL PRIMARY KEY,
   event_name VARCHAR(255) NOT NULL,
   event_type VARCHAR(100),
   event_timestamp TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
   event_data JSONB,
   user_id INT,
   user_ip INET,
   is_active BOOLEAN DEFAULT TRUE,
   created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
   updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE users (
   user_id SERIAL PRIMARY KEY,
   name VARCHAR(100),
   country VARCHAR(50),
   platform VARCHAR(50)
);

INSERT INTO events (event_name, event_type, event_timestamp, event_data, user_id, user_ip)
SELECT
   'Event ' || gs::text AS event_name,
   CASE
       WHEN random() < 0.5 THEN 'click'
       WHEN random() < 0.75 THEN 'view'
       WHEN random() < 0.9 THEN 'purchase'
       WHEN random() < 0.98 THEN 'signup'
       ELSE 'logout'
   END AS event_type,
   NOW() - INTERVAL '1 day' * (gs % 365) AS event_timestamp,
   jsonb_build_object('key', 'value' || gs::text, 'additional_info', 'info_' || (gs % 100)::text) AS event_data,
   GREATEST(1, LEAST(1000, FLOOR(POWER(random(), 2) * 1000) + 1)) AS user_id,
   ('192.168.1.' || ((gs % 254) + 1))::inet AS user_ip
FROM
   generate_series(1, 1000000) gs;

INSERT INTO users (name, country, platform)
SELECT
    first_names[first_idx] || ' ' || last_names[last_idx] AS name,
    CASE
        WHEN random() < 0.25 THEN 'India'
        WHEN random() < 0.5 THEN 'USA'
        WHEN random() < 0.7 THEN 'Germany'
        WHEN random() < 0.85 THEN 'China'
        ELSE 'Other'
    END AS country,
    CASE
        WHEN random() < 0.2 THEN 'iOS'
        WHEN random() < 0.4 THEN 'Android'
        WHEN random() < 0.6 THEN 'Web'
        WHEN random() < 0.75 THEN 'Windows'
        WHEN random() < 0.9 THEN 'MacOS'
        ELSE 'Linux'
    END AS platform
FROM
    generate_series(1, 1000) AS seq
    CROSS JOIN LATERAL (
        SELECT
            array['Alice', 'Bob', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Hank', 'Ivy', 'Jack', 'Liam', 'Olivia', 'Noah', 'Emma', 'Sophia', 'Benjamin', 'Isabella', 'Lucas', 'Mia', 'Amelia', 'Aarav', 'Riya', 'Arjun', 'Ananya', 'Wei', 'Li', 'Huan', 'Mei', 'Hans', 'Klaus', 'Greta', 'Sofia'] AS first_names,
            array['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', 'Martinez', 'Taylor', 'Anderson', 'Thomas', 'Jackson', 'White', 'Harris', 'Martin', 'Thompson', 'Moore', 'Lee', 'Perez', 'Sharma', 'Patel', 'Gupta', 'Reddy', 'Zhang', 'Wang', 'Chen', 'Liu', 'Schmidt', 'Müller', 'Weber', 'Fischer'] AS last_names,
            1 + (seq % 32) AS first_idx,
            1 + ((seq / 32)::int % 32) AS last_idx
    ) AS names;
SQL
```

```text theme={null}
Timing is on.
CREATE TABLE
Time: 86.029 ms
CREATE TABLE
Time: 80.962 ms
INSERT 0 1000000
Time: 7120.357 ms (00:07.120)
INSERT 0 1000
Time: 84.807 ms
```

NVMe 스토리지 덕분에 `c6gd.large`(가장 작은 사양)에서는 100만 행 삽입이 약 7초 만에 완료됩니다. 쿼리로 확인하세요. 데이터는 `random()`으로 생성되므로 실행할 때마다 행 수가 달라집니다:

```bash theme={null}
psql "$PG_URL" -c "SELECT event_type, COUNT(*) FROM events GROUP BY event_type ORDER BY 2 DESC;"
```

<div id="part-2-replicate">
  ## 파트 2: ClickHouse로 복제하기
</div>

<div id="create-clickhouse-service">
  ### ClickHouse 서비스 생성
</div>

같은 리전에 서비스를 생성하고 응답을 저장하십시오. 비밀번호는 생성 시 응답에만 표시됩니다:

```bash theme={null}
clickhousectl cloud service create \
  --name quickstart-ch \
  --region us-east-1 \
  --json > ch.json

CH_ID=$(jq -r .service.id ch.json)
CH_PASSWORD=$(jq -r .password ch.json)
```

실행 중이 될 때까지 기다리세요; ClickPipe에는 실행 중인 대상이 필요합니다:

```bash theme={null}
while [ "$(clickhousectl cloud service get "$CH_ID" --json | jq -r .state)" != "running" ]; do
  sleep 15
done
```

대신 기존 서비스를 사용하려면 `clickhousectl cloud service list`에서 `CH_ID`를 설정하고, `pg_clickhouse` 단계에 필요한 해당 서비스의 `default` 사용자 password를 `CH_PASSWORD`로 설정하십시오.

<div id="replicate-to-clickhouse">
  ### 테이블을 ClickHouse로 복제
</div>

ClickHouse 서비스에서 Managed Postgres 호스트명을 대상으로 Postgres CDC ClickPipe를 생성하세요. 이 파이프는 기존 행을 복사한 후, 이후 발생하는 변경 사항도 반영하여 ClickHouse와 계속 동기화합니다:

```bash theme={null}
PG_HOST=$(jq -r .hostname pg.json)
PG_PASSWORD=$(jq -r .password pg.json)

clickhousectl cloud clickpipe create postgres "$CH_ID" \
  --name quickstart-sync \
  --host "$PG_HOST" \
  --pg-database postgres \
  --username postgres \
  --password "$PG_PASSWORD" \
  --table-mapping public.events:public_events \
  --table-mapping public.users:public_users \
  --json > pipe.json

PIPE_ID=$(jq -r .id pipe.json)
```

참고:

* 복제된 테이블(Replicated Tables)은 `--table-mapping` 대상 이름으로 ClickHouse 서비스의 `default` 데이터베이스에 생성됩니다
* publication과 replication slot은 자동으로 생성되며, publication은 매핑된 테이블 범위로 설정됩니다. 직접 관리하는 publication을 사용하려면 `--publication-name`을 전달하세요
* Postgres의 직접 호스트명을 사용하세요. PgBouncer를 통한 복제는 지원되지 않습니다

<div id="wait-for-pipe">
  ### 파이프가 Running 상태가 될 때까지 기다리기
</div>

파이프는 `Running` 상태가 되기 전에 `Provisioning`, `Setup`, 그리고 (테이블이 큰 경우) `Snapshot` 단계를 거칩니다. 서비스에서 첫 번째 파이프가 `Running` 상태에 도달하는 데는 약 4분이 걸립니다. `Failed`와 `InternalError`는 최종 상태입니다:

```bash theme={null}
while :; do
  STATE=$(clickhousectl cloud clickpipe get "$CH_ID" "$PIPE_ID" --json | jq -r .state)
  case "$STATE" in
    Running) break ;;
    Failed|InternalError) echo "ClickPipe entered terminal state: $STATE" >&2; exit 1 ;;
  esac
  sleep 15
done
```

<div id="query-clickhouse">
  ### ClickHouse에서 복제된 데이터 쿼리하기
</div>

CLI에서 ClickHouse 서비스에 직접 SQL을 실행합니다. 처음 호출하면 Query API 엔드포인트와 서비스 범위의 API Key가 자동으로 프로비저닝됩니다:

```bash theme={null}
clickhousectl cloud service query --id "$CH_ID" \
  --query "SELECT count() FROM public_events"
```

```text theme={null}
Provisioning Query API endpoint + key for service 'quickstart-ch'...
1000000
```

Postgres에 새로 기록되는 데이터는 지속적으로 복제됩니다. 행을 삽입한 다음 개수가 1,000,001이 될 때까지 폴링하세요(일반적으로 1분 이내).

```bash theme={null}
psql "$PG_URL" -c "INSERT INTO events (event_name, event_type, user_id, user_ip) VALUES ('cdc-test', 'click', 42, '10.0.0.1');"

while [ "$(clickhousectl cloud service query --id "$CH_ID" \
  --query "SELECT count() FROM public_events")" != "1000001" ]; do
  sleep 10
done
```

<div id="query-clickhouse-from-postgres">
  ### Postgres에서 ClickHouse 쿼리하기
</div>

[`pg_clickhouse`](/docs/ko/products/managed-postgres/extensions/pg_clickhouse/introduction) 확장 기능을 사용하면 Postgres를 트랜잭션 데이터와 분석 데이터를 모두 아우르는 통합 쿼리 계층으로 사용할 수 있습니다. 먼저 ClickHouse HTTPS 호스트명을 확인한 다음, `psql`에서 확장 기능을 설정하십시오:

```bash theme={null}
CH_HOST=$(clickhousectl cloud service get "$CH_ID" --json \
  | jq -r '.endpoints[] | select(.protocol=="https") | .host')

psql "$PG_URL" <<SQL
CREATE EXTENSION pg_clickhouse;
CREATE SERVER ch FOREIGN DATA WRAPPER clickhouse_fdw
       OPTIONS(driver 'http', host '$CH_HOST', dbname 'default', port '8443');
CREATE USER MAPPING FOR CURRENT_USER SERVER ch
       OPTIONS (user 'default', password '$CH_PASSWORD');
CREATE SCHEMA organization;
IMPORT FOREIGN SCHEMA "default" FROM SERVER ch INTO organization;
SQL
```

Heredoc은 의도적으로 따옴표로 감싸지 않았으므로, SQL이 Postgres에 전달되기 전에 셸이 `$CH_HOST`와 `$CH_PASSWORD`를 치환합니다. 이제 복제된 테이블이 `organization` 스키마의 외부 테이블(foreign table)로 표시되며, 해당 테이블에 대한 쿼리는 ClickHouse에서 실행됩니다.

이 데이터셋을 사용해 `c6gd.large`에서 측정한 결과, 분석 쿼리는 외부 테이블을 통해 실행할 때 6\~9배 더 빠르게 실행됩니다(예: 5개 집계 GROUP BY는 ClickHouse 경유 시 176ms, 로컬에서는 1,133ms이며, 집계가 포함된 JOIN은 298ms 대 2,764ms입니다).

<div id="cleanup-resources">
  ## 정리
</div>

먼저 ClickPipe를 삭제한 다음 Postgres 서비스를 삭제하십시오. 서비스를 삭제하면 해당 서비스의 모든 데이터가 영구적으로 삭제됩니다:

```bash theme={null}
clickhousectl cloud clickpipe delete "$CH_ID" "$PIPE_ID"
clickhousectl cloud postgres delete "$PG_ID"
```

실행 중인 ClickHouse 서비스는 바로 삭제할 수 없습니다. 먼저 중지하고 `stopped` 상태가 될 때까지 기다린 다음 삭제하세요:

```bash theme={null}
clickhousectl cloud service stop "$CH_ID"

while [ "$(clickhousectl cloud service get "$CH_ID" --json | jq -r .state)" != "stopped" ]; do
  sleep 10
done

clickhousectl cloud service delete "$CH_ID"
```
