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

> 实时访问服务器配置中所定义集群上的数据库表，并将 `SELECT` 和 `INSERT` 查询转发到该集群。

# 集群

`Cluster` 数据库引擎支持实时访问服务器配置中所定义集群上的数据库表。它相当于 [`Remote`](/docs/zh/reference/engines/database-engines/remote) 数据库引擎的命名集群版本，两者的关系与 [`cluster`](/docs/zh/reference/functions/table-functions/cluster) 和 [`remote`](/docs/zh/reference/functions/table-functions/remote) 表函数之间的关系相同。

系统会按需从集群获取表列表及其结构，因此数据库始终反映集群的当前状态。每个表都以命名集群上的 [`Distributed`](/docs/zh/reference/engines/table-engines/special/distributed) 存储形式提供，并将 `SELECT` 和 `INSERT` 查询转发到该集群。

这种方式适合联合多个 ClickHouse 集群，也可以将整个集群接入 `clickhouse-local` 或另一集群，而无需逐一指定地址：只需在配置中定义一次集群，即可一并指定各副本的凭证、安全连接和服务器间通信密钥。

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

```sql theme={null}
CREATE DATABASE cluster_db
ENGINE = Cluster('cluster_name', 'database');
```

**引擎参数**

* `cluster_name` — 服务器配置中的集群名称 (参见[集群](/docs/zh/reference/engines/table-engines/special/distributed#distributed-clusters)) ，用法与 `Distributed` 表引擎相同。支持 `{cluster}` 等[宏](/docs/zh/reference/settings/server-settings/settings/other#macros)，每次访问时都会展开。
* `database` — 集群上的数据库名称。

与 `Remote` 数据库引擎不同，`Cluster` 引擎不接受凭证参数，也不存储机密信息：连接使用集群配置中各副本的设置 (用户、密码、安全连接、压缩以及服务器间通信密钥) 。每次访问时都会根据配置重新解析集群，因此数据库会像 `Distributed` 表一样，随配置重新加载和[集群自动发现](/docs/zh/guides/oss/deployment-and-scaling/cluster-discovery)的结果而更新。创建数据库时，集群必须存在；如果之后集群从配置中消失，服务器仍会启动，但数据库会报告集群缺失，直到配置中重新出现该集群。

指向当前服务器的副本会被视为本地分片：`SELECT` 和 `INSERT` 直接以当前用户身份执行，因此该用户需要拥有底层数据库及其表的相应特权；配置的集群凭证仅用于远程副本。如果某个分片的本地副本没有该数据库或某张表，查找便会回退到该分片的远程副本，与 [`Distributed`](/docs/zh/reference/engines/table-engines/special/distributed) 表一样。

当集群有多个分片时，每个代理表都会从所有分片读取数据，但元数据——表列表及其结构——只取自其中一个分片 (优先选择本地分片) ，与 [`cluster`](/docs/zh/reference/functions/table-functions/cluster) 表函数一样。这样，列出表只需一次查询，而不必逐一查询每个分片。因此，集群中的各分片应提供相同的表集合；如果一张表只存在于部分分片，代理表仍会提供该表，但查询会在缺少该表的分片上失败。向多分片数据库中的表执行 `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 TABLES` 或 `EXISTS TABLE` 的结果中，按名称查找该表会报告 `UNKNOWN_TABLE`；该表没有可供查询的代理表。如果一张表存在于作为解析来源的分片上，但另一个分片缺少该表，则该表可见，但代理查询可能在缺少该表的分片上失败。

`Cluster` 代理表不存在可重新执行的等效定义，因此 `SHOW CREATE TABLE` 会报告 `THERE_IS_NO_QUERY` 错误。以下情况也包括在内：

* 当前通过上述远程副本回退机制提供该表 (某个分片的本地副本没有该数据库或该表) 。覆盖整个集群的 `Distributed` 表不会进行这种回退，而回退后使用的集群子集也没有自己的名称。
* 数据库的集群名称包含宏。`Cluster` 在每次访问时展开这些宏，而 `Distributed` 仅在创建表时展开宏，因此配置变更后，无论使用宏表达式还是其当前展开结果重新创建表，都无法重现相同的行为。
* 重新加载配置可能使单分片集群变为多分片集群。此时，运行中的代理表会获得隐式 `rand()` 键，用于分配通过 `INSERT` 插入的行，而重新加载前序列化的表没有该键。无条件序列化该键也不等效，因为这会让独立的 `Distributed` 表在读取时使用它进行分片裁剪；`CREATE TABLE` 无法表达仅用于插入的分片键。

<h2 id="notes">
  注意事项
</h2>

* 该引擎提供集群的透传视图：不支持对 `Cluster` 数据库执行 `CREATE TABLE`、`DROP TABLE`、`ALTER` 等 DDL 语句。请直接在集群上管理 schema，例如使用 [`ON CLUSTER`](/docs/zh/reference/statements/distributed-ddl) DDL 语句。
* 远程服务器会根据集群定义中配置的用户检查访问权限 (如果集群使用服务器间通信密钥，则根据当前用户检查) ；本地也会根据用户对数据库及其表拥有的常规特权检查访问权限。
* `Remote` 数据库引擎的行为细节——本地分片上表的可见性规则、表列表是否完整、集群不可用时如何报告错误，以及代理数据库链——同样适用于 `Cluster` 引擎；详见该引擎的[注意事项](/docs/zh/reference/engines/database-engines/remote#notes)。

<h2 id="example">
  示例
</h2>

创建一个 `Cluster` 数据库，使其指向服务器配置中集群 `test_shard_localhost` 的 `default` 数据库，然后使用该数据库：

```sql theme={null}
CREATE DATABASE cluster_db
ENGINE = Cluster('test_shard_localhost', 'default');
```

```sql theme={null}
SHOW TABLES FROM cluster_db;
```

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

```sql theme={null}
SELECT * FROM cluster_db.t;
```
