性能优化 · 大数据运维

待环境验证

ClickHouse 查询与内存瓶颈诊断

关联 Query Log、运行中内存与 EXPLAIN,定位扫描、聚合、排序和 JOIN 放大,并验证分布式查询资源预算。

ClickHouse大数据监控告警
阅读导引 · 理解后再操作

这篇知识解决什么问题

以一个可关联的查询 ID 区分客户端等待、服务端扫描和中间结果内存。通过本地日志、运行中指标与计划逐层收窄,再扩展到实际参与分片;性能改写必须先保持 JOIN 多匹配、聚合精度和结果完整性。

同一查询需要分清观察层级

客户端时间、query_log 最终事件、processes 当前内存与主机 RSS 口径不同。用查询 ID、执行节点和统一时间窗关联,保留日志刷新或采样缺口,不能简单相减得出泄漏或把所有子查询读数无条件求和。

计划解释范围,样本验证收益

EXPLAIN 可以展示索引裁剪和执行结构,却不提供真实并发吞吐。先看 Parts、Granules 和 JOIN 放大,再用受控数据对比结果与资源;25.9 及以上索引展示还要核对官方要求的查询设置。

进入文章正文
关联架构图解5 个组件 · 点击展开

场景图的客户端与 Distributed 入口提示发起端,本地表节点提示各分片执行与存储。图没有画出每次查询的实际节点集合和最终聚合阶段,不能将单节点内存或多个子查询的指标直接当作整个集群峰值。

查看场景架构与实施步骤
参考架构 · 非实时拓扑

ClickHouse 合并、副本与查询运维架构

联查 MergeTree parts、查询内存、复制队列和备份恢复,区分本地表、分片与副本,完成有界诊断和隔离验收。

  • 数据 / 请求
  • 控制 / 管理
  • 观测 / 查询

点击组件,在图下方查看职责;连线编号对应流向解读。小屏可横向滚动,或直接展开文字说明。

ClickHouse 合并、副本与查询运维架构:组件关系图联查 MergeTree parts、查询内存、复制队列和备份恢复,区分本地表、分片与副本,完成有界诊断和隔离验收。 客户端 / Distributed → 分片本地表:路由与执行;分片本地表 → 同分片其他副本:数据副本同步;分片本地表 → Keeper 协调:复制协调;同分片其他副本 → Keeper 协调:副本进度协调;分片本地表 → 独立备份目的地:独立备份。箭头说明见下方流向解读。
逻辑参考图,待环境验证。以开源自建 ClickHouse 的 MergeTree / ReplicatedMergeTree 为主线,执行前 SELECT version() 并对照对应版本字段。ClickHouse Cloud 使用不同的存储与运维机制,应采用服务文档。

客户端 / Distributed

入口 / 来源

示意路由到目标分片,Distributed 自身不等同底层持久数据副本。

查看关联工具
全部组件职责 5 个组件
客户端 / Distributed
示意路由到目标分片,Distributed 自身不等同底层持久数据副本。工具介绍 客户端 / Distributed
分片本地表
保存当前分片的数据 parts,排序键与分区用于数据组织。工具介绍 分片本地表
同分片其他副本
复制同一分片的数据,不能当作额外不同分片计算总数据量。工具介绍 同分片其他副本
Keeper 协调
协调复制元数据;数据 parts 不通过 Keeper 存储。工具介绍 Keeper 协调
独立备份目的地
保存备份数据和所需元数据,完整性仍需恢复演练证明。
流向解读 5 条连接
  1. 1

    客户端 / Distributed 分片本地表

    数据 / 请求 · 路由与执行

    本地表执行当前分片查询;跨分片聚合由入口查询计划协调。

  2. 2

    分片本地表 同分片其他副本

    数据 / 请求 · 数据副本同步

    示意同一复制组间获取数据 parts,不意味着所有写入必须先经过这个节点。

  3. 3

    分片本地表 Keeper 协调

    控制 / 管理 · 复制协调

    本地副本使用协调服务维护复制元数据。

  4. 4

    同分片其他副本 Keeper 协调

    控制 / 管理 · 副本进度协调

    其他副本独立维护复制进度和协调会话。

  5. 5

    分片本地表 独立备份目的地

    数据 / 请求 · 独立备份

    按经过核实的备份范围持久保存可恢复来源。

故障域与操作边界

适用版本与部署模式

以开源自建 ClickHouse 的 MergeTree / ReplicatedMergeTree 为主线,执行前 SELECT version() 并对照对应版本字段。ClickHouse Cloud 使用不同的存储与运维机制,应采用服务文档。

数据与变更边界

不自动执行 OPTIMIZE FINAL、删除 parts、重建 Keeper 路径或生产 RESTORE。分片分摊数据,副本复制数据;Distributed 表不凭自身保存底层全部数据。

架构依据与版本核对 2 篇官方资料

图解是本站基于官方资料整理的逻辑参考;实施前仍需核对实际部署版本、组件支持范围与变更审批。

适用范围与取证边界

本文用于 ClickHouse 查询变慢、内存限制异常和分布式查询放大的定位。以自建 MergeTree 分片为主要场景,参考当前官方 SQL 与系统表文档;先记录实际版本、发起节点、目标表引擎和查询 ID。25.9 起 EXPLAIN indexes 的展示有特别设置要求,旧版本不可直接套用所有新参数。

示例只读取一台已确认节点的系统表或解释一个有限范围的查询计划,未执行生产压测,验证等级为 PENDING。系统日志可能包含业务字面量和身份信息,示例优先提取查询 ID、指标与错误码,完整 SQL 另行脱敏保存。

把客户端等待与服务端耗时分开

用户看到的响应时间包括连接池排队、代理、网络、服务端执行和结果传输。先用 query ID 关联服务端记录,不能拿客户端一秒超时直接推断服务端执行了一秒。超时重试可能让原查询与新查询重叠,进一步放大并发和内存。

分布式查询有发起查询和子查询;比较两个版本时固定数据范围、并发、缓存条件及 SQL 参数。先定位受影响模板,再查几个具体执行实例,避免用所有查询平均值掩盖长尾或把大范围历史分析与日常报表混成一组。

从 Query Log 找到相同对象

SELECT event_time, query_id, initial_query_id, type,
       query_duration_ms, read_rows, read_bytes,
       memory_usage, exception_code
FROM system.query_log
WHERE event_date >= today() - 1
  AND event_time >= now() - INTERVAL 15 MINUTE
  AND initial_query_id = 'REPLACE_WITH_INITIAL_QUERY_ID'
  AND type IN ('QueryFinish', 'ExceptionWhileProcessing',
               'ExceptionBeforeStart')
ORDER BY event_time DESC
LIMIT 20
SETTINGS max_execution_time = 5, max_threads = 2;

查询限定已知 ID 和时间窗,同时避免把 QueryStart 与最终事件重复统计。日志存在刷新延迟,采样配置也可能省略部分执行;空结果不能直接证明请求未到达。分布式场景按明确的相关节点逐一取证,initial_query_id 可关联同一执行链中的子查询,但并非所有后台派生任务都保留该链。system.query_log

当前内存与历史记录分别解释

运行中的查询可在目标节点读取当前值及当前峰值,先通过 DESCRIBE TABLE system.processes 核实字段存在。

SELECT query_id, initial_query_id, elapsed,
       read_rows, read_bytes, memory_usage, peak_memory_usage
FROM system.processes
WHERE initial_query_id = 'REPLACE_WITH_INITIAL_QUERY_ID'
ORDER BY memory_usage DESC
LIMIT 10
SETTINGS max_execution_time = 5, max_threads = 2;

system.processes.memory_usage 是当前查询内存,可能不包含全部专用分配;进程 RSS、后台合并、缓存和并发查询仍需独立看。历史 query_log 的内存字段也不能直接与某一时刻 RSS 相减来求「泄漏」。若 OS 或容器 OOM 杀进程,单条 SQL 日志可能不完整,应关联宿主机记录。system.processes

用 EXPLAIN 核对数据跳过

以下计划示例使用建模文章中的沙箱表,仅用于已经准备好的有限演练数据。实际表不存在时停止,不替换成任意生产大表。

EXPLAIN indexes = 1
SELECT event_type, count()
FROM sandbox.events_design_demo
WHERE tenant_id = 7
  AND event_time >= toDateTime('2026-09-01 00:00:00', 'UTC')
  AND event_time < toDateTime('2026-09-02 00:00:00', 'UTC')
GROUP BY event_type
SETTINGS use_query_condition_cache = 0,
         use_skip_indexes_on_data_read = 0;

此处两个查询设置遵循 25.9 及以上版本的官方展示要求;旧版本先核对支持情况,再使用本版本 EXPLAIN 语法。观察过滤前后的 Parts 和 Granules,判断分区、主键与跳过索引是否缩小读取范围。EXPLAIN 不提供真实吞吐证明,索引被使用也不等于足够有效;需要与受控执行记录的读取量对照。EXPLAIN 说明

区分聚合、排序与 JOIN 的放大

高基数 GROUP BY 会保留大量聚合状态,宽列排序需要更多数据和中间结果,JOIN 则可能在构建侧形成大的哈希表。先看过滤是否足够早、连接键是否重复、连接结果是否成倍扩张,再讨论内存参数。

将 JOIN 改成 ANY、改写为 IN、预聚合或使用字典都有语义前提。ANY 会改变多匹配结果,近似去重函数也会改变精度,不能只因更快就替换。JOIN 算法与自动选择能力随版本演进,应以实际计划和官方兼容范围决定,不默认某种算法适用于所有连接类型。JOIN 设计与优化

内存限制与落盘需要一起预算

max_memory_usage 是单服务器上单查询的内存限制,不是整个分布式查询的全局总额。节点上还存在多个查询、后台工作和进程开销;把它提高到机器内存总量容易转成系统 OOM。max_bytes_before_external_group_bymax_bytes_before_external_sort 分别控制聚合、排序使用外部存储的相关阈值。

外部聚合或排序会消耗临时磁盘容量和带宽,也不保证所有算子或合并阶段都不再用大量内存。评估前核对临时目录、余量和并发,优先保持 throw 语义,避免使用返回部分结果的 overflow 配置却把不完整数据当作成功报表。查询复杂度限制

从单节点扩展到相关分片

本地 query_log 正常不代表整个 Distributed 查询正常;需要关联发起节点和实际参与分片的记录。读取行数在发起节点与子节点可能存在不同汇总口径,不应全部相加形成一个虚假的总扫描量。慢分片、网络传输或发起端最终聚合都可能成为瓶颈。

只选择对应查询实际访问的节点,避免在事故中对全部副本做无界日志扫描。核对是否启用了跳过不可用分片等设置,返回成功也可能不符合业务完整性要求。后台合并和查询争用资源时,应结合已有时间线判断,不能通过停止所有合并制造短暂更快的查询。Distributed 引擎

验收、常见误区与停止回退

使用固定结果样本比较变更前后值、行数和精度,并比较代表性并发下的延迟分布、读取量、内存、临时磁盘与错误率。查询 LIMIT 通常限制输出,不保证前面的聚合或排序只处理少量数据;时间与读取限制也不是操作系统级硬隔离,需保留观察和取消渠道。

常见误区是只加内存、只看第一次冷查询、把当前使用量当作整次峰值,以及以返回部分结果消除报错。若临时磁盘接近预算、出现新 OOM 或结果不一致,停止试验并恢复原 SQL 或查询级设置。保留 query ID、计划和配置差异;已落地的错误结果需独立撤回或重算,不能只让下一次查询成功就结案。

相关阅读:MergeTree 数据设计副本与备份运维

参考资料

从现象到判断

先收集证据,再缩小范围。以下是判读路径,不代表已经确认根因或获准变更。

  1. 客户端多次超时,但服务端只有较短执行记录,或相同模板出现重叠查询。

    只读核对
    用请求和 query ID 对齐连接池、代理、服务端最终事件以及重试起止时间。
    如何判读
    可能是执行之外等待或重试放大;客户端超时不能直接转成服务端耗时。
  2. 查询结果很少,read_rows 和内存却很高,LIMIT 没有明显降低资源消耗。

    只读核对
    解释过滤、聚合、排序及 JOIN 的计划顺序,核对输入基数和裁剪比例。
    如何判读
    中间结果可能远大于输出;LIMIT 不保证前置算子只读取少量数据,应先定位放大阶段。
  3. 开启外部聚合后内存错误减少,但临时磁盘增长和整体延迟恶化。

    只读核对
    关联聚合与排序阈值、并发、临时存储容量和 I/O,比较相同输入下的结果。
    如何判读
    压力可能转移到落盘路径;外部计算不取消全部内存需求,需按实际资源预算决定。
常见误区与判断边界 2 项

提高单查询额度直到不再报错

单服务器的查询限制不是全局内存,也不覆盖所有并发和后台工作。盲目增大可能变成容器或 OS OOM,应先解释扫描与中间结果,再评估节点总预算。

用语义变化换取更快查询

ANY JOIN、近似聚合和返回部分结果的 overflow 策略都会影响业务含义。改写前固定精度和多匹配规则,结果不同就应停止推广,不能只用延迟下降验收。

交接时应留下的证据

作为记录提纲使用,不是自动检查结果;未取得的证据应标记缺口,并注明负责人。

  • 保存脱敏 SQL、query ID、发起节点、版本和实际参与分片,明确客户端与服务端时间。
  • 关联最终日志事件、当前及峰值内存、主机 RSS、后台任务和日志采样缺口。
  • 归档索引裁剪与算子计划、输入基数、临时存储预算及固定样本的结果对照。
  • 记录代表性并发下的延迟、读取量和错误率,并保存查询级设置差异及停止阈值。

记录需包含环境、版本、时间与时区;分享前脱敏,不附访问令牌、密码或完整业务敏感数据。

继续阅读与资料核对

补充相关主题,再结合当前环境的实施记录形成结论。

返回原理导读

DOUYA OPS ECOSYSTEM

贡献你的经验,帮助更多运维人

把故障复盘、标准流程和最佳实践沉淀为可检索、可复用的知识内容。