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

# 解决 ClickHouse 中“parts 过多”异常

> 了解如何通过对插入进行批处理、使用异步插入以及选择合适的分区键，来诊断并解决“parts 过多”异常。

<div id="what-the-exception-means">
  ## 该异常的含义
</div>

当某个 `INSERT` 会使 `MergeTree` 表中的活跃数据分区片段数量超过已配置的限制时，ClickHouse 会抛出 `parts 过多` 异常。该异常通常还会包含消息：`Merges are processing significantly slower than inserts`。

每个同步 `INSERT` 至少会创建一个数据分区片段。如果一次 insert 包含属于多个分区值的行，ClickHouse 可能会为每个受影响的分区各创建一个 parts。后台合并会将较小的 parts 合并为较大的 parts；但如果新 parts 的创建速度快于 ClickHouse 的合并速度，活跃 parts 的数量就会持续增长。

该异常可能由以下任一设置触发：

* [`parts_to_throw_insert`](/zh/reference/settings/merge-tree-settings/parts-to#parts_to_throw_insert)，用于限制单个分区中的活跃 parts 数量。
* [`max_parts_in_total`](/zh/reference/settings/merge-tree-settings/max-parts#max_parts_in_total)，用于限制表中的活跃 parts 总数。

<div id="diagnose-the-cause">
  ## 诊断原因
</div>

使用以下查询找出活跃 parts 数量最多的分区：

```sql theme={null}
SELECT
    database,
    table,
    partition_id,
    count() AS active_parts,
    sum(rows) AS rows,
    formatReadableSize(sum(bytes_on_disk)) AS size_on_disk
FROM system.parts
WHERE active
  AND database = '<database_name>'
  AND table = '<table_name>'
GROUP BY
    database,
    table,
    partition_id
ORDER BY active_parts DESC;
```

要检查由 `max_parts_in_total` 对整个表施加的限制，请统计表中的所有活跃 parts：

```sql theme={null}
SELECT
    database,
    table,
    count() AS active_parts,
    sum(rows) AS rows,
    formatReadableSize(sum(bytes_on_disk)) AS size_on_disk
FROM system.parts
WHERE active
  AND database = '<database_name>'
  AND table = '<table_name>'
GROUP BY
    database,
    table;
```

常见原因包括：

* 频繁进行小批量同步插入。
* 分区键基数过高。
* 单次插入包含来自多个分区值的行。
* 由于存储吞吐量受限、可用磁盘空间不足或其他资源争用，后台合并跟不上。

你可以在 [`system.merges`](/zh/reference/system-tables/merges) 中查看当前正在运行的合并任务，并查阅服务器日志中的合并失败记录。

<div id="resolve-the-exception">
  ## 解决此异常
</div>

<div id="batch-synchronous-inserts">
  ### 批次同步插入
</div>

在插入前，先在客户端将数据行分批。每个批次应至少包含 1,000 行，理想情况下为 10,000–100,000 行。目标是大约每秒执行一次同步 `INSERT`。插入次数更少、单次插入量更大，可以生成更少的 parts，并减少后台合并所需的工作量。

<div id="use-asynchronous-inserts">
  ### 使用异步插入
</div>

如果不方便在客户端进行批处理，请使用[异步插入](/zh/concepts/best-practices/selecting-an-insert-strategy#asynchronous-inserts)，这样 ClickHouse 就能在服务端对传入数据进行批处理：

```sql theme={null}
INSERT INTO <table_name>
SETTINGS
    async_insert = 1,
    wait_for_async_insert = 1
VALUES (...);
```

保持 `wait_for_async_insert = 1`，这样 ClickHouse 只会在数据成功写入后才确认插入。

<div id="review-the-partitioning-key">
  ### 检查分区键
</div>

使用低基数的分区键，并避免按用户或请求标识符等值进行分区。ClickHouse 仅会在同一分区内合并 parts，因此分区数量过多会妨碍高效合并。有关建议，请参阅[选择分区键](/zh/concepts/best-practices/partitioning-keys)。

<div id="investigate-merge-bottlenecks">
  ### 排查合并瓶颈
</div>

如果插入操作已经进行了适当的批处理，请检查存储性能、可用磁盘空间以及相互争用的后台任务。合并速率取决于存储系统、表引擎、排序键、压缩，以及可用的 CPU 和 I/O 能力。

<div id="avoid-increasing-part-limits-as-the-primary-fix">
  ### 不要把提高 part 限制作为首要修复措施
</div>

提高 `parts_to_throw_insert` 或 `max_parts_in_total` 并不能解决 parts 过多创建的根本原因。提高限制虽然可以推迟异常出现，但也可能增加文件系统和元数据开销，并降低查询性能。只有在找出原因并确认系统容量充足后，才应更改这些设置。

<div id="verify-the-recovery">
  ## 验证恢复情况
</div>

更改插入策略或分区方案后，再次运行诊断查询。活跃 parts 的数量应趋于稳定，并随着后台合并逐渐跟上而开始下降。继续监控插入失败、可用磁盘空间以及 [`system.merges`](/zh/reference/system-tables/merges)，直到积压清空。
