ClickHouse 查询报 MEMORY_LIMIT_EXCEEDED(Code 241),或把节点内存打满后被 OOM Killer 终止。
查询直接失败并返回 Memory limit (for query) exceeded 或 Memory limit (total) exceeded,异常码 241;也可能节点 RSS 飙升后被内核 OOM Kill,system.query_log 里留下未正常结束的查询。常见于大聚合、大 JOIN 和排序查询。
先让日志落盘,再看失败查询的峰值内存:
clickhouse-client --query "SYSTEM FLUSH LOGS"
clickhouse-client --query "SELECT event_time, query_id, user, formatReadableSize(peak_memory_usage) AS peak, formatReadableSize(memory_usage) AS mem, read_rows, result_rows, exception_code, substring(query, 1, 100) FROM system.query_log WHERE event_time > now() - INTERVAL 2 HOUR AND exception_code = 241 ORDER BY event_time DESC LIMIT 10 FORMAT Vertical"
再看当前正在运行的查询:
clickhouse-client --query "SELECT query_id, elapsed, formatReadableSize(memory_usage) AS mem, read_rows, substring(query, 1, 120) FROM system.processes ORDER BY memory_usage DESC LIMIT 10"
clickhouse-client --query "SELECT metric, value FROM system.metrics WHERE metric IN ('MemoryTracking', 'Query', 'QueryThread')"
核对查询限额与服务端上限:
clickhouse-client --query "SELECT name, value FROM system.settings WHERE name IN ('max_memory_usage', 'max_memory_usage_for_user', 'max_threads', 'max_bytes_before_external_group_by', 'max_bytes_before_external_sort', 'max_block_size', 'join_algorithm')"
clickhouse-client --query "SELECT name, value FROM system.server_settings WHERE name LIKE 'max_server_memory%'"
system.query_log 里的 peak_memory_usage 才是关键,system.processes.memory_usage 只是当前值。若查询已结束,先 SYSTEM FLUSH LOGS 再查,否则看不到最新记录。
易误判:把 max_memory_usage 设为 0 只是取消单查询上限,仍受 max_server_memory_usage(默认约 0.9×RAM)和用户配额约束;报错的那条查询也未必是元凶 —— 并发查询合计可能先触发服务端总限额。
GROUP BY/DISTINCT,聚合状态按 key 常驻内存。LIMIT 的大排序,或聚合后才排序;外部排序未启用。max_threads 过大,每线程缓冲和块叠加放大单查询内存。SELECT *、缺少分区裁剪、未用 PREWHERE,中间结果过大。FINAL、窗口函数、arrayJoin 放大行数或触发额外合并。max_threads(如 4–8),或限制该用户的并发。PREWHERE,只读必要列,先过滤再聚合。uniqCombined、quantile 等近似函数。max_bytes_before_external_group_by ≈ max_memory_usage / 2,排序同理设置 max_bytes_before_external_sort。grace_hash/partial_merge 等可落盘算法。FINAL,用 argMax 或预去重表替代;控制 arrayJoin 的放大倍数。max_memory_usage_for_user 和并发配额,与在线用户隔离。peak_memory_usage 的 p99、MemoryTracking 和 memory.events,按用户设阈值告警。max_memory_usage=0 仍可能触发内存限制?memory_usage 还是 peak_memory_usage?max_server_memory_usage(默认约 0.9×RAM)、用户配额和并发合计限制。peak_memory_usage;memory_usage 只是采样时的当前值,会漏掉瞬时峰值。max_threads 和 max_bytes_before_external_group_by(排序场景再加 max_bytes_before_external_sort)。