Paths analytics query OOMs on multi-day windows for high-volume projects (uses 14-18 GiB of ClickHouse memory)
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 5/5
- 预计耗时
- 一周以上
- 新手友好度
- 42/100
- Issue 类型
- 缺陷
- 描述清晰度
- 需要澄清
- 活跃度
- 冷清
- 技术栈
- clickhouse, typescript
调研方向
从 Paths 分析查询和仪表板入口开始,然后查看 self-hosting/ 文档以及现有的 cohort_events_mv、dau_mv 和 event_property_values_mv 定义。使用 ClickHouse 查询日志测量来复现 8 天的工作负载;完成标准是选择一种能够避免报告的内存故障的缓解措施,或清楚地说明安全范围限制。
由索引模型根据 Issue 内容生成。
描述
Summary
The Paths analytics query (multi-CTE WITH session_paths AS (WITH paths_deduped_cte AS (WITH ordered_events AS ...)) aggregation) consumes 14–18 GiB of ClickHouse memory for an 8-day window on a project with ~1.5 billion screen_view events. With typical per-query memory limits, the query fails with Code 241 MEMORY_LIMIT_EXCEEDED and the dashboard surfaces it to users as Failed to execute 'json' on 'Response': Unexpected end of JSON input.
Setup
- Self-hosted OpenPanel via the
self-hosting/directory (runninglindesvard/openpanel-{api,dashboard,worker}:2) - ClickHouse
25.10.2.65 - ~1.46 billion total events; ~1.5 billion
screen_viewevents on the affected project - Resource limits in our deployment:
max_memory_usage = 16 GB(per query)max_server_memory_usage_to_ram_ratio = 0.85(24 GiB cgroup → 20.40 GiB server cap)max_concurrent_select_queries = 80
The query (captured from system.query_log exception_code = 241)
WITH session_paths AS (
WITH paths_deduped_cte AS (
WITH ordered_events AS (
SELECT session_id, concat(origin, path) as path, created_at
FROM events
WHERE project_id = '<redacted>'
AND name = 'screen_view'
AND path != '' AND path IS NOT NULL
AND created_at BETWEEN toDateTime('2026-05-25 00:00:00')
AND toDateTime('2026-06-02 00:00:00')
ORDER BY session_id ASC, created_at ASC
)
SELECT session_id,
arraySlice(
arrayFilter(
(x, i) -> i = 1 OR x != paths_raw[i - 1],
groupArray(path) AS paths_raw,
arrayEnumerate(paths_raw)
),
1, 5
) AS paths_deduped
FROM ordered_events
GROUP BY session_id
)
SELECT session_id, ..., paths[1] AS entry_page
FROM paths_deduped_cte HAVING length(paths) >= 2
)
SELECT entry_page, count() AS count
FROM session_paths
GROUP BY entry_page
ORDER BY count DESC LIMIT 3 FORMAT JSON
Observed memory usage
From system.query_log ExceptionWhileProcessing events on 2026-06-01 with our 16 GB per-query cap (= 14.90 GiB binary):
| event_time | mem_used | "would use" |
|---|---|---|
| 13:15:03 | 13.68 GiB | 17.46 GiB |
| 13:14:55 | 14.16 GiB | 16.47 GiB |
| 13:14:48 | 14.46 GiB | 18.46 GiB |
| 13:14:32 | 14.69 GiB | 18.47 GiB |
The query needs ~17–18 GiB to complete on an 8-day window for our event volume.
Why this is hard to mitigate from the operator side
The query uses groupArray(path) to materialize all events per session into an array, then arrayFilter to dedupe consecutive duplicates. Both operators hold the per-session aggregation state in memory. With ~300M screen_view events in an 8-day window distributed across many sessions, the per-thread aggregation state grows large.
arrayFilter and groupArray don't spill to disk via max_bytes_before_external_group_by — that setting only applies to direct GROUP BY materialization. So even with disk-spill enabled (we have it at 11 GB), this query stays entirely in RAM.
This means there's no purely operator-side fix; raising the per-query cap past ~20 GiB starts to risk OOM against the cgroup, and raising the cgroup means giving CH a larger share of host RAM at the expense of other containers.
Suggestions (in increasing order of effort)
- Document the memory cost in
self-hosting/docs. Operators of large self-hosted instances should know Paths analytics is memory-heavy. - UI date-range cap or warning on the Paths dashboard — suggest shorter ranges for high-volume projects, or warn before submitting if a heuristic projects high cost.
- Pre-aggregated session-paths materialized view at write time (similar to the existing
cohort_events_mv,dau_mv,event_property_values_mv). The dashboard could read a small summary rather than recomputing from raw events on every load. - Stream-aware rewrite — replace
groupArray(path)+arrayFilterwith a window function approach (CH 22+ has solid window function support) that can stream rather than buffer all paths per session.
Workaround we're using
- Raised
max_memory_usageto 16 GB so the median Paths query succeeds - Communicated to users that the Paths dashboard for high-volume projects should use 3–4 day ranges for now
Happy to provide additional data (full query text, EXPLAIN, system.query_log excerpts, EXPLAIN ESTIMATE) if useful.
Versions
lindesvard/openpanel-api:2,lindesvard/openpanel-dashboard:2,lindesvard/openpanel-worker:2(Docker Hub:2tag)- ClickHouse:
clickhouse/clickhouse-server:25.10.2.65 - Self-hosting layout: this repo's
self-hosting/
- 主要语言
- TypeScript
- 星标
- 7.2k
- 派生
- 523
- 平均合并
- 15 小时 45 分钟
- 30 天内合并 PR
- 40
环境准备
- 提供 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 没有贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
Openpanel-dev/openpanel 的其他 Issue
-
Insights never generated on self-hosted: daily job filters on raw `subscriptionStatus = 'active'`可能已有人在做 @grootbro 于 2 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 76/100
Openpanel-dev/openpanel#597 · 2 条评论 ·
维护者通常 1 天内回复
-
Duplicate /track requests return plain text 'Duplicate event', SDK throws JSON parse error可能已有人在做 @grootbro 于 2 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 76/100
Openpanel-dev/openpanel#579 ·
维护者通常 1 天内回复
-
ClickHouse retry logs print CLICKHOUSE_URL with its password可能已有人在做 @ppjsw 于 5 天前认领。 未关闭
难度 1/5 1-3 小时 新手友好度 92/100
Openpanel-dev/openpanel#551 · 1 条评论 ·
维护者通常 1 天内回复
-
login page needs refinement可能重新可做 关联的 PR 已关闭且未合并。 未关闭
难度 2/5 1-3 小时 新手友好度 68/100
Openpanel-dev/openpanel#495 ·
维护者通常 1 天内回复
-
Session-grouped queries treat every sessionless event as one session (wrong results, ClickHouse OOM)可能已有人在做 @grootbro 于 2 天前认领。 未关闭
难度 4/5 3-5 天 新手友好度 52/100
Openpanel-dev/openpanel#575 ·
维护者通常 1 天内回复
查看 Openpanel-dev/openpanel 的全部 Issue
相似的 Issue
-
a10y a10y-audit ai-driven-qa claude
难度 2/5 1-3 小时 新手友好度 86/100
linagora/twake-directory-manager#219 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100
维护者通常 1 天内回复
-
type: bug
难度 2/5 1-3 小时 新手友好度 79/100
维护者通常 1 天内回复
-
0️⃣ phase/new
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
Pulse v7: buildPreferencesFromTelos() bypasses telosSectionOrFile(), renders empty on unified-TELOS installs可能已有人在做 @zephyr91 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 75/100
danielmiessler/LifeOS#2393 ·
维护者通常 4 天内回复