> ## 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.

> 可实时访问远程 ClickHouse 服务器上数据库中的表，并将 `SELECT` 和 `INSERT` 查询转发到该服务器。

# Remote

`Remote` 和 `RemoteSecure` 数据库引擎可通过原生 TCP 协议实时访问远程 ClickHouse 服务器上某个数据库中的表。它们相当于 ClickHouse 到 ClickHouse 场景下的 [`MySQL`](/docs/zh/reference/engines/database-engines/mysql) 和 [`PostgreSQL`](/docs/zh/reference/engines/database-engines/postgresql) 数据库引擎。

表列表及其结构会按需从远程服务器拉取 (底层使用 `SHOW TABLES` 和 `DESCRIBE TABLE`) ，因此该数据库始终反映远程服务器的当前状态。每个表都会以 [`Distributed`](/docs/zh/reference/engines/table-engines/special/distributed) 存储的形式提供，该存储基于所提供的地址构建临时集群，并将 `SELECT` 和 `INSERT` 查询转发至远程服务器。

这对于联合多个 ClickHouse 集群，或将较大的 ClickHouse 集群接入 `clickhouse-local` 或较小的集群非常方便。

<div id="creating-a-database">
  ## 创建数据库
</div>

<Tabs>
  <Tab title="Remote" id="remote">
    如果省略端口，`Remote` 将通过普通 TCP 端口连接 (`tcp_port`，默认值为 `9000`) 。

    ```sql theme={null}
    CREATE DATABASE remote_db
    ENGINE = Remote('addresses_expr', 'database'[, 'user'[, 'password']]);
    ```
  </Tab>

  <Tab title="RemoteSecure" id="remote-secure">
    如果省略端口，`RemoteSecure` 将通过安全 TCP 端口 (`tcp_port_secure`，默认值为 `9440`) 建立安全 TLS 连接。

    ```sql theme={null}
    CREATE DATABASE remote_db
    ENGINE = RemoteSecure('addresses_expr', 'database'[, 'user'[, 'password']]);
    ```
  </Tab>
</Tabs>

**引擎参数**

* `addresses_expr` — 远程服务器地址，或用于生成多个地址的表达式，格式为 `host` 或 `host:port`。地址表达式支持与 [`remote`](/docs/zh/reference/functions/table-functions/remote) 表函数相同的 glob 模式 (例如 `{a,b,c}`、`{N..M}` 和 `{a|b}`，可展开为多个分片和副本) 。如果省略端口，`Remote` 使用普通 TCP 端口 (`tcp_port`，默认值为 `9000`) ，`RemoteSecure` 使用安全 TCP 端口 (`tcp_port_secure`，默认值为 `9440`) 。
* `database` — 远程服务器上的数据库名称。
* `user` — 远程用户名。可选，默认值：`default`。
* `password` — 远程用户密码。可选，默认值：空。

地址和凭据存储在数据库定义中，因此 `SHOW CREATE DATABASE` 会隐藏密码。与 `remote` 表函数一样，指向当前服务器的地址会被视为本地分片：`SELECT` 和 `INSERT` 会直接以当前用户身份执行，因此该用户必须拥有底层数据库及其表的相应特权；存储的凭据仅用于真正的远程服务器。如果某个分片的本地副本没有该数据库或表，查找将像 [`Distributed`](/docs/zh/reference/engines/table-engines/special/distributed) 表一样回退到该分片的远程副本。在这种情况下，`SHOW CREATE TABLE` 输出的是实际生效的回退地址 (从各分片中剔除本地副本) ，而非配置的地址，因此生成的 `Remote(...)` 表定义能够重建实际处理查询的对象。

当地址表达式描述多个分片时，每个代理表都会从所有分片读取，但元数据——表列表及其结构——与 [`remote`](/docs/zh/reference/functions/table-functions/remote) 表函数一样，取自任意一个分片 (优先本地分片) ，这样列出表只需执行一次查询，而不是每个分片执行一次。因此，集群中的各分片应提供相同的一组表；如果某张表仅存在于部分分片上，对该表的代理查询会在没有该表的分片上失败。向多分片数据库中的表执行 `INSERT` 时，每一行都会被发送到随机分片 (代理 `Distributed` 表具有隐式的 `rand()` 分片键) ；若要为查询指定分片，请设置 [`insert_shard_id`](/docs/zh/reference/settings/session-settings/insert#insert_shard_id)。该隐式键仅用于分配插入的行：读取时，该表的行为与没有分片键的 `Distributed` 表相同 (尤其是，[`optimize_skip_unused_shards`](/docs/zh/reference/settings/session-settings/optimize-skip#optimize_skip_unused_shards) 和 [`force_optimize_skip_unused_shards`](/docs/zh/reference/settings/session-settings/force-optimize#force_optimize_skip_unused_shards) 不会将其视为分片裁剪键) 。`SHOW CREATE TABLE` 会在生成的 `Remote(...)` 表定义中包含该键，因此基于该定义重新创建的表也能接受多分片 `INSERT` 查询。

也支持命名集合：

```sql theme={null}
CREATE DATABASE remote_db
ENGINE = Remote(my_named_collection, database = 'default');
```

<div id="notes">
  ## 注意事项
</div>

* 该引擎是远程服务器的直通视图：不支持对 `Remote` 数据库执行 `CREATE TABLE`、`DROP TABLE`、`ALTER` 等 DDL 语句。请直接在远程服务器上管理 schema。
* 对已配置的远程用户，访问权限由远程服务器强制执行；本地则按数据库及其表上的常规特权进行控制。
* 用户无权查看的本地分片表会被视为缺失，而非禁止访问。因此，不能通过 `Remote` 数据库探测用户无权访问的本地数据库中的表名。这既适用于列出表 (`SHOW TABLES`、`EXISTS TABLE`) ，也适用于解析表 (`DESCRIBE TABLE`、`SHOW CREATE TABLE`、`SELECT`) ；此类表也不会通过其所在分片的远程副本提供。只有在本地副本确实没有该表时，才会触发上述回退机制。
* 列出某个分片的本地副本中存在的数据库的表时，结果还会包含仅存在于该分片远程副本上的表，以确保 `SHOW TABLES` 和 `system.tables` 与会回退到这些副本的 `EXISTS TABLE`、`DESCRIBE TABLE` 和 `SELECT` 保持一致。当所有远程副本均未响应时，将原样返回本地副本的表列表，因为它已是可用副本的响应结果。
* 如果远程服务器不可用，列出其表 (`SHOW TABLES`、`system.tables`) 时会报告连接错误，而不是返回空表列表，这与对同一数据库执行 `EXISTS TABLE` 和 `SELECT` 时的行为一致。请注意，当此类数据库无法访问时，查询所有数据库的 `system.tables` 的 `SELECT` 也会失败。
* 一个 `Remote` 数据库可以指向同一服务器上的另一个 `Remote` 数据库。列出和描述此类链中的表无需拥有中间数据库的特权——它既不保存自身的数据，也不保存自身的元数据，并且每一跳都会检查调用方对其所代理对象的权限。相比之下，读取和写入数据需要在链的每一跳都拥有 `SELECT` / `INSERT` 权限，因为查询实际是在中间数据库的表上执行的，这与在另一个 `Distributed` 表之上使用 `Distributed` 表完全相同。上述可见性规则同样适用于该链：中间数据库对调用方隐藏的表，也不会通过外层数据库的远程副本提供。如果本地副本上的中间数据库无法访问其自身的目标，外层分片的本地副本将完全无法响应——就如同该副本本身已宕机——外层数据库会回退到该分片的远程副本。

<div id="example">
  ## 示例
</div>

创建一个指向远程服务器 `system` 数据库的 `Remote` 数据库，并从中读取数据：

```sql theme={null}
CREATE DATABASE remote_system
ENGINE = Remote('127.0.0.1:9000', 'system', 'default', '');
```

```sql theme={null}
SHOW TABLES FROM remote_system LIKE 'one';
```

```text theme={null}
┌─name─┐
│ one  │
└──────┘
```

```sql theme={null}
SELECT * FROM remote_system.one;
```

```text theme={null}
┌─dummy─┐
│     0 │
└───────┘
```
