关于 diagnosing-endpoint-performance
面向调查特定缓慢、高成本或不可靠端点的诊断技能。它检查缓存、物化资格、查询历史和调用成本,给出具体建议;修改查询前需获得用户确认。
主要功能
- 01检查端点配置与版本
- 02评估缓存 TTL 和物化
- 03读取物化拒绝原因
- 04查看端点调用频率与成本
- 05建议缓存、物化、改写或回滚
适用场景
- 01诊断超时的端点
- 02评估高成本端点的调用模式
- 03判断查询是否可物化
- 04检查近期端点版本回归
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ posthog/ skills --skill diagnosing-endpoint-performance安装后在 Claude Code 中输入/diagnosing-endpoint-performance确认已加载。
详细介绍
诊断端点性能
此技能将分析某个具体的端点,该端点可能速度慢、成本高或不可靠,并给出明确的建议。它是 auditing-endpoints(用于发现候选端点)的深度分析对应技能。
何时使用此技能
- “这个端点速度慢/超时了”
- “为什么我的端点触及了成本上限?”
- “我应该物化 X 吗?”
- 某个端点在
auditing-endpoints中被发现,其物化失败或调用成本高 - 用户心中已有特定端点,并希望获得建议
如果问题涉及整个项目(“我应该清理哪些内容?”),请先使用 auditing-endpoints。
可用工具
| 工具 | 用途 |
|---|---|
endpoint-get | 完整的端点配置:查询、当前版本、data_freshness_seconds、物化状态 |
endpoint-versions | 每个版本的历史记录(查询及物化状态);以及当前版本 |
endpoint-materialization-status | 是否符合物化条件、当前状态、上次运行时间、上次错误 |
endpoints-materialization-preview | 物化后的查询会是什么样,以及不符合条件时的拒绝原因 |
endpoints-last-execution-times | 上次调用时间(用于检查端点是否仍在使用) |
execute-sql | 查询 query_log,查看端点级调用频率以及每次调用的时长/字节数 |
决策树
决定给出什么建议时,请按以下顺序逐项检查——最先适用的选项就是成本最低的修复方式。
第 1 步——是否已缓存?
获取端点并查看 data_freshness_seconds(它既设置缓存 TTL,也设置物化后的刷新频率)。如果用户的流量在此时间窗口内重复使用相同参数调用端点,那么首次调用之后的每次调用都会命中缓存,实际无需付费。
- TTL 为默认值(24h / 86400s),且数据无需比这更新鲜 → 无需更改。
- TTL 为下限 900s(15 min),且用户每分钟调用端点多次 →
提高 TTL。这几乎总是成本最低的首选操作。(
data_freshness_seconds是一个枚举值:900、1800、3600、21600、43200、86400、604800——最短间隔为 15 分钟。) - TTL 已处于下限,因为数据必须保持最新(例如,实时仪表盘)→ 缓存无济于事,转到第 2 步。
变量的取值方式在这里很重要:如果每次调用都传入不同的 user_id 或 date_from 值,缓存会有许多不同的键,提高 TTL 的帮助就较小。如果几乎每次调用都使用少数几种相同的参数组合,缓存就会很有用。
步骤 2 — 是否应该进行物化?
物化会预先计算查询,并将结果保存为定期刷新的视图。读取速度会接近即时响应,但代价是数据会因刷新间隔而过时,还需要为物化本身消耗存储和计算资源。
调用 endpoints-materialization-preview。响应会告诉你:
- 符合条件且转换逻辑简洁 → 强烈建议物化。尤其是筛选形态可预测的端点(变量、细分维度)。
- 不符合条件,并附有拒绝原因 → 无法物化。原因通常会提示下一步该怎么做(见步骤 3 — 重写)。
- 符合条件,但转换逻辑复杂(范围对很多、需要复杂地重新推导聚合结果)→ 物化可以正常运行,但可能节省不了多少资源。在启用前值得先说明这一点。
启用物化后,调用方必须传入所有已物化变量——不带这些变量的调用会被拒绝(安全性:防止返回未筛选的数据)。建议启用时,同时注明哪些变量会成为必填项。
步骤 3 — 查询是否需要重写?
对于不符合物化条件的 SQL 端点,endpoints-materialization-preview 返回的拒绝原因是首要依据。该工具始终会解析成功。查看原因,并与以下要点匹配——这些要点概括了常见情况,并未涵盖服务端执行的所有检查;如果两者不一致,应以原始原因为准。手动提出重写方案:
- 因群组细分 / 对比模式被拒绝 → 常规属性细分可以正常物化;只有群组细分会被阻止。将群组细分改为属性细分。趋势端点支持物化对比模式;其他查询类型则应移除对比模式(改为将对比时间窗口作为变量)。
- JOIN 与变量组合使用 → 顶层
JOIN加变量筛选会被拒绝物化,因为应用变量会改变连接后的行基数,并悄然产生错误结果(例如,LEFT JOIN中不匹配的行会丢失变量列)。调整结构,让变量只筛选单个表——将筛选条件推入随后再进行连接的子查询 / CTE,而不是跨连接筛选。这是最常见的“看起来没问题,却无法物化”的陷阱。 - “缺少变量” / 无界扫描 → 查询在没有筛选条件的情况下读取了过多数据。建议添加必填的时间窗口变量(例如
date_from、lookback_days)。 - HogQL 使用
*/ 非确定性函数 → 缩小所选列的范围,并尽可能用变量替换now()/today()。 - 没有要点匹配 → 上面的列表并不完整;实时检查会拒绝更多形式,包括
OR中的变量、与另一个变量比较的变量、HAVING子句中的变量、不受支持的运算符,以及无法物化的查询类型。将拒绝原因原样告知用户,并直接据此分析,而不要强行套用最接近的要点。有些原因根本没有等效的重写方式——例如OR {variables.x} = 'all'这种可选变量写法——应明确说明这一点,而不是改变查询的行为。
检查 endpoint-versions,确认查询近期是否有变更。回归问题往往源于某个特定提交,回退到该版本通常比重写更快。
第 4 步——实际调用的是慢版本吗?
默认只运行最新版本;只有调用方固定 ?version=N 时才会运行旧版本。因此,通常需要调整的是当前版本——除非问题出在某个固定使用的旧版本上。调用 endpoint-versions 并查看每个版本的 last_executed_at,以了解最近调用过哪些版本;如果某个物化版本的 last_executed_at 为 null 或已过时很久,那么与其调整,不如考虑取消物化或删除(请先确认——该信号只统计 API 密钥调用,可能较为稀疏)。
如需了解端点级调用频率和单次调用成本,请使用 execute-sql 查询 query_log——其中包含 query_duration_ms、read_rows 和 read_bytes,便于确认该端点调用的实际开销:
SELECT count() AS calls, max(query_start_time) AS last_called, avg(query_duration_ms) AS avg_ms
FROM query_log
WHERE name = '<endpoint_name>' AND endpoint LIKE '%/endpoints/%' AND is_personal_api_key_request
工作流
- 按名称识别端点。如果用户提供了 URL,请从
/api/projects/{team_id}/endpoints/{name}/run中解析名称。 - 使用
endpoint-get获取完整配置。注意:data_freshness_seconds、is_materialized、当前版本和查询类型。 - 使用
endpoint-materialization-status查看物化状态(是否失败?是否符合条件?)。 - 使用
endpoint-versions查看查询历史以及当前版本(除非调用方固定?version=N,否则调用方会使用该版本)。 - 如果用户提供了具体问题(“超时”“内存限制”“非常慢”),请按上述决策树逐步排查。否则,请说明这四项检查点,并询问用户符合哪一种情况。
- 最后给出明确建议——提高 TTL、物化、重写或回滚,并在执行前确认。
交互示例
User: "monthly_active_users is timing out for some callers"
Agent steps:
- endpoint-get monthly_active_users → HogQL endpoint, data_freshness_seconds=900,
is_materialized=false, current version v4
- endpoint-materialization-status monthly_active_users → not materialised; eligible: true
- endpoint-versions monthly_active_users
→ v4 is current; v1–v3 are prior query revisions (callers hit v4 unless pinned)
- endpoints-materialization-preview → eligible, clean transform with one range pair
- "Three things stand out:
1. Cache TTL is 900 seconds (the 15-min floor), but the data is
aggregating a month — that aggressive a refresh probably isn't
necessary. Bumping to 1 hour (3600s) would dramatically reduce
ClickHouse load.
2. It's eligible for materialisation with a clean transform. If
callers can tolerate 5-15 minute staleness, materialisation
would make reads near-instant.
3. v4 is the current version, so callers hit it by default — the
tuning target is clear.
Quickest win: bump TTL to 3600s. Bigger win: materialise.
Which trade-off matches your needs? If you need real-time freshness,
neither helps and we'd need to rewrite the query — likely narrowing
the aggregation window."
重要说明
- 缓存几乎总是首选解决方案。 它无需成本、可立即撤销,也不会改变数据语义。如果提高 TTL 就能解决问题,请不要急着选择物化。
- 物化存在隐性成本。 包括物化视图的存储、刷新计算,以及调用方必须传入所有变量这一要求。
- 不要擅自重写查询。 修改查询会创建新版本,并可能导致调用方无法正常工作!!!请先说明建议的修改并获得同意,再执行。
- 有三种使用情况信号。
endpoint-get的last_executed_at表示端点级的最近调用时间;endpoint-versions提供各版本自己的last_executed_at;query_log(通过execute-sql查询)提供端点级调用频率和单次调用成本。这些信号都只统计个人 API 密钥调用,而且各版本的最近调用记录可能较为稀疏——在认定某个版本已停用之前,请先向用户确认。 - “合适的”解决方案取决于 SLA,而非查询本身。 在建议物化之前,务必询问用户可接受的数据陈旧程度。对于实时仪表板,即使成本很低,存在 15 分钟延迟的物化视图也不合适。
- 告知 PostHog 缺少什么。 如果诊断遇到产品限制(资格规则、TTL 枚举值、必需变量),请通过
agent-feedback提醒团队。