> ## 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 命令行客户端](/docs/zh/products/cloud/features/cli) (`clickhousectl`) 和 `psql` 完成 ClickHouse Managed Postgres 的预配、数据加载、将数据复制到 ClickHouse 以及查询。命令均为非交互式；`clickhousectl` 可通过 `--json` 输出 JSON。

<div id="prerequisites">
  ## 前置条件
</div>

安装 ClickHouse 命令行客户端：

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

你还需要 `psql` (PostgreSQL 客户端工具；在 macOS 上，使用 `brew install libpq`) 和 `jq`。

写操作 (创建、删除) 需要通过 [API key 身份验证](/docs/zh/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">
  ## 第 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、主机名以及可直接使用的连接字符串：

```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">
  ### 等待服务预配完成
</div>

预配需要几分钟。持续轮询，直到状态变为 `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
```

若要改用现有服务，请将 `CH_ID` 设置为 `clickhousectl cloud service list` 中显示的值，并将 `CH_PASSWORD` 设置为该服务 `default` 用户的密码，`pg_clickhouse` 步骤需要用到它。

<div id="replicate-to-clickhouse">
  ### 将表复制到 ClickHouse
</div>

在 ClickHouse 服务上创建一个 Postgres CDC ClickPipe，并将其指向 Managed Postgres 的主机名。该管道会先复制现有行，然后持续将后续变更同步到 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)
```

注意：

* 复制表会落在 ClickHouse 服务的 `default` 数据库中，名称由 `--table-mapping` 的目标决定
* publication 和 replication slot 会自动创建，其中 publication 的作用范围仅限于映射的表；传入 `--publication-name` 可改用你自行管理的 publication
* 请直接使用 Postgres 主机名；不支持通过 PgBouncer 进行复制

<div id="wait-for-pipe">
  ### 等待管道进入 Running 状态
</div>

管道在进入 `Running` 之前，会依次经过 `Provisioning`、`Setup`，以及 (对于较大的表) `Snapshot` 状态。在一个服务上创建的第一个管道通常需要约 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>

直接通过命令行客户端向 ClickHouse 服务执行 SQL。首次调用会自动预配一个 Query API 端点和一个服务级作用域的 API 密钥：

```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 (通常不到一分钟) ：

```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/zh/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 加引号，这样 shell 就会在 SQL 到达 Postgres 之前先替换 `$CH_HOST` 和 `$CH_PASSWORD`。现在，这些复制表会在 `organization` schema 中显示为 foreign tables；对它们发起的查询实际上会在 ClickHouse 中执行。

在使用该数据集的 `c6gd.large` 上测得，通过 foreign tables 运行分析查询的速度可提升 6-9 倍 (例如，一个包含 5 个聚合的 GROUP BY：通过 ClickHouse 为 176 ms，本地执行为 1,133 ms；一个带聚合的 JOIN：298 ms，而本地为 2,764 ms) 。

<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"
```
