
ClickHouse 性能结论判定规则如何从 CI 噪声中识别真实回归与真实优化【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse本文围绕 ClickHouse 仓库中.claude/skills/perf-comparison性能对比技能的判定参考文档verdict-rules.md展开系统讲解 ClickHouse 在评估 PR 性能测试结果时使用的一套证据驱动判定框架判定工作的职责是判断一个性能结果是否“可采取行动”actionable而不是机械复述仪表盘上的某一行数据。读完本文你将掌握一张完整的证据核对表、七种判定结论的适用条件、跨多次 PR 运行与 master 历史趋势的解读规则以及如何写出可评审、可追溯的性能结论报告——这套规则同时适用于阅读 CI/仪表盘数据与本地perf.py复现结果两种场景。判定任务的定位结论不等于复述仪表盘在 ClickHouse 的研发流程中.claude/skills/perf-comparison/SKILL.md定义了一个核心问题Is this ClickHouse performance result real, flaky/noisy, already known from history, or worth deeper investigation?即这次性能结果是真实变化、偶发噪声、历史上已知波动还是值得深入调查判定技能的职责由此明确为判断结果是否 actionable——当一份性能测试表被呈现在你面前你的任务不是重新声明“这一行比那一行慢/快”而是综合 CI 差分、多次运行、置信度、master 历史、覆盖率与火焰图等多路证据给出一个有依据的判定。因此 verdict-rules 文档首先强调一个纪律没有任何单条证据可以单独定案。原文档.claude/skills/perf-comparison/references/verdict-rules.md与 SKILL 都指出两类典型错误仅凭一个 changed row 就判定回归为真实未核对重复运行与历史趋势没有任何历史/趋势证据就武断地把回归当成 flaky。下文的所有规则都是为了让结论有据可查、可复现、可被同行评审。证据核对表Evidence checklistverdict-rules 给出了一张面向每个可疑变化suspicious change的八行证据核对表。判定者应尽量为每一行填上“强信号”或“弱/噪声信号”而不是只挑对自己结论有利的一列EvidenceQuestionStrong signalWeak/noisy signalChanged metric原始差分是否超过阈值差异大方向一致仅勉强超过阈值Repeated PR runs该变化是否在多天/多次运行中复现同一 query/metric/arch 反复出现只出现一次/消失/方向翻转Confidence置信度保持还是下调tier/reason 支持原始变化命名的检查项解释了原因tier 为 noise/suspect自适应阈值或原始样本将证据降级Trend/history所选运行是否落在正常散布范围之外超出 p95/近期区间历史稳定落在近期 p95 以内存在频繁尖峰/突变点Related metricsCPU/real/client/memory 是否彼此一致各项指标方向一致指标互相矛盾Coverage/PR diffPR 是否触达了被测试执行到的代码改动的文件与覆盖文件相交无重叠或文件不相关Flamegraph栈增量能否解释指标变化热点与 PR/查询吻合热点缺失/无关/混杂Local run受控的本地对照能否复现可重复p 值显著一次性结果或受工具链偏差影响值得注意的是原文档的措辞表格既问了“是否有强证据”也明确列出“弱/噪声信号”是什么样——例如“barely above threshold”仅勉强超阈值、“appears once / disappears / flips”出现一次/消失/翻转等。填表过程中若多数行落在弱信号列判定自然倾向噪声或需重跑若多行落在强信号列才足以支撑真实回归。七种判定结论Verdict labelsreal regression真实回归当大部分下列条件成立时使用CI 差分高于阈值同一 query/metric/arch 在多次 PR 运行中重复出现或置信度数据支持历史数据中并不常见同样的随机波动相关指标CPU/real/client/memory方向一致PR/覆盖率关联合理或火焰图指向被改变的行为。verdict-rules 特别强调不必要求每一项都满足对缺失的证据要明确说明为什么缺失、为何不影响判定。比如没有火焰图数据时可写“flamegraph not available”而不是装作它支持了结论。likely noise疑似噪声当出现以下情形时使用变化的行只在一次 PR 运行中出现、后续运行中消失所选数值落在正常趋势/历史散布区间内如近期 p95 以内置信度模块下调了原始证据的等级相关指标与头条指标互相矛盾PR 与测试之间没有合理解释也没有 profile 证据支持。一个关键纪律即便如此仍然要把证明它是噪声的数据展示出来原文档原文 Still show the data that proves this而不是一句“可能是噪声”带过。类似地SKILL 也强调dismissal needs evidence——降噪同样要给出历史或重复运行数据。needs rerun需要重跑当以下情形出现时使用原始差分很大但置信度/历史/重复运行结果彼此矛盾只有一次运行存在结果接近阈值near threshold环境或基础设施可能扭曲了测量机器争抢、构建差异等本地结果与 CI 结果不一致。推荐动作Recommended action是重跑性能 CI或做一次聚焦的本地对照实验。从判定语义看needs rerun 是“证据冲突但值得再确认”而不是放弃。unstable test测试本身不稳定当以下情形出现时使用趋势/历史显示频繁出现同等量级的尖峰同一查询在不同运行中时而变慢、时而变快direction flips仪表盘将该指标标记为 unstable自对照或重复运行本身就噪声很大。verdict-rules 特意写了一条使用约束不要仅仅因为结果不合意inconvenient就使用此标签。unstable 必须由可展示的运行间波动数据支撑——比如后文 Report wording 一节给出的跨运行差分序列例子。real improvement真实优化判定门槛与real regression对称加速幅度高于阈值重复运行/置信度/历史数据支持它并不是随机不稳定的简单反向翻转即不是噪声的偶然回落。同时ci-api.md提醒一个细节当前置信度模块的 tier 名称/reason 可能是按变慢slowdown方向措辞的不要把速度提升行打印成confirmed_regression只有当周边证据支持时才把加速行称为 stable speedup/change。local-only evidence仅有本地证据当本地perf.py显示出有意义的结果但 CI/仪表盘证据缺失或尚未核对时使用。它的语义是本地结果在当前阶段只是本地证据直到与 CI/history 对照后才能升级判定。not enough evidence证据不足当缺少关键的“身份信息”identity时使用例如run 未知unknown runquery index 未知指标/架构选错wrong metric/arch历史不可得且没有重复运行或本地证据。这一类是最低信息条件下的兜底结论不要硬凑一个方向性结论。重复 PR 运行规则Repeated PR run rules检查某个 PR 时应列出该 PR 的全部 performance.ci 运行然后在不同运行间比较同一个 test/query/metric/archcurl -fsS $BASE/runs?q$PR | jq .其中$BASE为 performance.ci 的标准 API 前缀具体端点形态可参见 .claude/skills/perf-comparison/references/ci-api.md?q$PR返回该 PR 的所有运行注意搜索可能带回超集务必按identity.prNumber PR过滤。原文档给出的解读规则非常明确N/N 次重复出现且 diff 相似→ 强信号strong仅 1/N 出现一次→ 弱信号weak很可能需要重跑或属噪声除非 diff 极大且 profile 能解释方向反复翻转→ 测试不稳定unstable只有旧运行有该变化、最新运行干净→ 很可能已解决或属噪声最新运行在早期干净运行之后新出现了该变化→ 需要调查可能是 PR 新改动引入也可能是 master 基线移动导致。这些规则直接对应到 helper 脚本可对每个 PR 做跨运行对比# 列出某 PR 的所有 performance.ci 运行 python3 .claude/skills/perf-comparison/scripts/perf_api.py runs --pr $PR # 纵向对比某 test/query/metric/arch 在该 PR 全部运行中的表现oldest→newest diff 图表 python3 .claude/skills/perf-comparison/scripts/perf_api.py pr-query-history \ --pr $PR --test aggregation_in_order_2 --query-index 4 \ --metric client_time --arch armmaster / history 趋势规则判定噪声与真实效果的关键差异在于把所选运行放到 master 长期历史里看而不是凭感觉。verdict-rules 要求直接使用仪表盘的 trend/history 数据。支持 flakiness/noise 的证据所选点落在近期正常区间内例如低于/接近 p95没有该 PR 时也会出现同等量级尖峰置信度自适应阈值adaptive threshold大于原始效应changePoints显示 master 在 PR 运行前后存在基线突变periodComparisons显示历史上频繁出现类似的波动。支持“新 PR 效应”的证据所选点以有意义的倍数超出近期 p95历史中不存在可比的尖峰多次 PR 运行呈现同样的变动PR 确实改动了被覆盖且相关的代码。历史描述语句的“允许/禁止”清单verdict-rules 对报告措辞立了硬性格式规范✅ 必须使用的历史描述格式required wording形如History center trend: 976 points over 2026-04-24 → 2026-06-15; all p05/p50/p95 ..., recent 30 points over 22.7h p05/p50/p95 ...; candidate is 3.06x p95.即必须说明点的数量与时间跨度、给出历史总体分位数p05/p50/p95与近期窗口如最近 30 个点及其时间跨度的分位数并把候选运行与 p95 做倍数比较。❌ 禁止使用的历史描述forbidden wordingmin..., median-ish..., max..., last... .只报 min/max/median/last 无法反映散布形态无法支撑噪声与真实变化的区分。这条禁止项与ci-api.md的“required summary shape”互相印证要报周期、全量历史 p05/p25/p50/p75/p95、近期窗口 p05/p50/p95并将选中点的 old/new 值与 p50、p95 比较。覆盖率 / PR 关联规则Coverage 接口回答的问题是这个测试是否执行了 PR 所改动的代码它不能回答PR 是否导致了变慢——原文档用两句话划清了这条因果边界。因此 Coverage 只用于“表述可能性”phrase plausibilityintersectingFiles 0PR 改动与测试覆盖相交 → 关联合理应进一步查看改动 hunkPR 只改了文件、但与测试覆盖无重叠 → 关联不那么直接只有测试覆盖文件、PR 并未改动它们 → 可能是间接行为变化覆盖率数据不可用 → 明确写 unavailable退而求其次用 PR diff 与查询文本人工比对。对应的抓取方式fileSetintersecting返回 PR 改动与测试覆盖相交的文件集可取files[].path、files[].patch、coverageRanges等字段curl -fsS $BASE/runs/$RUN_ID/tests/$TEST/coverage?fileSetintersecting | jq .一个已观测到的 API 陷阱记录在 .claude/skills/perf-comparison/references/ci-api.md当相交文件数为 0 时响应可能省略totals.intersectingFiles需用len(files)作为 0 的兜底不要误判为“数据缺失”。火焰图Flamegraph规则火焰图只能用于精确匹配的证据组合run id、test、query index、metric、arch、trace type 全部一致跨维使用没有意义。解读方向CPU diff 栈在候选侧增长 → 计算热点compute hotspot候选Real 时间增长但 CPU 不增长 → 更可能是等待/I/O/锁/调度wait/lock/schedulerMemory trace 增长 → 更可能是内存分配压力allocation pressure。最重要的边界是如果栈增量无法与 query/PR 改动产生关联就不要声称找到了根因Do not claim root cause if stack delta does not connect to query/PR changes。报告措辞同样有硬性要求required wording首先给出 UI 查询页链接格式形如/runs/runId/tests/test/queries/queryIndex因为该页面内含 Flamegraphs 卡片原始 API 链接只作为机器可读的辅助证据backup列出 top sample deltas明确说明哪些栈帧是缺失的absent。❌ 禁止的模糊措辞forbidden wordingflamegraph diff exists and contains relevant samples.原文档评价这种说法 too vague to review过于含糊无法评审。SKILL 的推荐写法是给出一张“叶函数/子系统 | baseline samples | candidate samples | delta | interpretation”的表格。另外ci-api.md记录火焰图端点可能返回 404 或空帧——缺失火焰图数据是“证据缺席”不代表噪声报告里应写no frames returned/not available不能反过来当噪声证据用。本地 perf.py 规则本地复现只有在满足严格条件时才“有意义”meaningful足够的运行次数p 值 ≤ 0.05diff 超过测试阈值结果重要时能重复稳定数据集完全一致、服务器设置可比identical datasets and comparable server settings。本地结果在被 CI/history 核对之前只能按 local-only 上报Local-only result should be reported as local-only until checked against CI/history。这与判定标签local-only evidence呼应。本地对照的标准姿势详见 .claude/skills/perf-comparison/references/local-perf.md是对旧/新两个二进制各起一个隔离 server再用仓库自带的tests/performance/scripts/perf.py跑同一份性能测试 XMLmkdir -p tmp tests/performance/scripts/perf.py \ --host 127.0.0.1 127.0.0.1 \ --port 9000 9001 \ --runs 7 \ tests/performance/aggregation_in_order_2.xml | tee tmp/aggregation_in_order_2.perf.tsv然后用本技能的解析器把输出转成可读报告python3 .claude/skills/perf-comparison/scripts/parse_perf_py.py tmp/aggregation_in_order_2.perf.tsv解析器.claude/skills/perf-comparison/scripts/parse_perf_py.py实现了几条与本规则一致的判定逻辑值得对照阅读源码阈值取自 perf.py 输出的report-threshold行判定函数verdict(diff, pvalue, threshold)abs(diff) threshold→ within thresholdpvalue 0.05→ not statistically significant否则按 diff 正负判 candidate slower / candidate fasterdiff 行为(new_median - old_median) / old_median正为变慢、负为变快无diff行时提示 either only one server was used, too few samples were collected, or no query passed perf.pys diff/p-value gate。也就是说“超过阈值 p≤0.05 足够运行数 可重复”这些门槛都被写进了工具层而非仅停留在文档约定。报告措辞示例好写法与坏写法verdict-rules 用成对的正反例说明了什么叫“可评审的报告措辞”。以下引用均来自原文档逐条保留了格式要求。好写法Good——结论由证据链导出而非表格复述The latest PR run showsaggregation_in_order_2/4client_time/armat23.2%, above a21.7%threshold. The same query appears in 3/4 PR runs, history does not show comparable spikes, and coverage intersectssrc/AggregateFunctions/...; verdict: real regression, medium confidence.这条例文完整串联了证据核对表的多个维度原始 diff 与阈值、跨运行复现次数、历史无同类尖峰、覆盖率与src/AggregateFunctions/...相交——最后才落到 verdict 与 confidence 等级。坏写法Bad——直接把表格行为当结论This is a regression because the table says slower.坏写法Bad——输出仪表盘内部代码而不解释SKILL 的第 4 条核心原则也禁止这一点Confidence:M1:downgrade, M2:neutral, M3:downgrade.好写法Good——把置信度翻译成 tier reason 具名检查项Confidence tier isnoise: History Adaptive Threshold downgraded because observed 47.2% is below the 94.8% threshold from recent master noise; Raw Sample Evidence also downgraded.坏写法Bad——无数据支撑的模糊断言Cross-run behavior is unstable.好写法Good——用完整跨运行序列证明不稳定Cross-run chart oldest→newest: -15.3%, 19.8%, 6.6%, -10.7%, 15.3%, -15.6%, -3.1%, 22.5%; direction flips repeatedly, so verdict: unstable.好写法Good——用更新的重跑结果取代旧数据并说明取代理由The latest rerun no longer reproduces the earlier24%row: the same test/query/metric/arch is now1.2%, below threshold. The older row is superseded, so verdict: likely noise or resolved.坏写法Bad——在更新的干净重跑之后仍展示旧的24%表格而不加任何解释。这组正反例背后是一条贯穿始终的原则报告必须区分“当前被接受的有效证据”与“已被取代的探索性旧数据”新旧矛盾时要亮出更可信的一方并说明为什么。判定规则在仓库中的工程支撑这套判定规则并非孤立的文档而是 ClickHouse 仓库中一整套“性能对比技能”的组成部分各文件职责如下仓库文件职责.claude/skills/perf-comparison/SKILL.md技能入口总体原则、数据源优先级、证据阶梯11 步、报告模板、常见错误清单.claude/skills/perf-comparison/references/verdict-rules.md本文主体判定标签与各维度证据解读规则.claude/skills/perf-comparison/references/ci-api.mdperformance.ci API 的端点、字段与实测陷阱confidence、trend、history、coverage、flamegraph.claude/skills/perf-comparison/references/local-perf.md本地 perf.py、server 启动、数据集与二进制来源约定.claude/skills/perf-comparison/scripts/perf_api.py汇总 CI/API 数据的 helperruns、pr-inventory、query、pr-query-history、master-checks 等.claude/skills/perf-comparison/scripts/parse_perf_py.py解析本地 perf.py TSV 输出并给出 verdict.claude/skills/perf-comparison/scripts/test_perf_api.py对分类逻辑的测试复刻了ci/jobs/scripts/perf/compare.sh的 changed/unstable 判定tests/performance/aggregation_in_order_2.xml例文中的具体性能测试含 substitution、create/fill/query 结构tests/performance/scripts/perf.py本地性能测试运行器输出report-threshold/diff ... pvalue供判定tests/performance/scripts/compare_perf_tsv.pyTSV 级比较工具例文中的aggregation_in_order_2是仓库里真实存在的性能测试该 XML 将optimize_aggregation_in_order等设置写入settings用substitution把uniqs取 100/10000/1000000 三种规模对一张 30 分区的 MergeTree 表执行sum/groupArray/uniqExact三种分组聚合查询tests/performance/aggregation_in_order_2.xml。因此aggregation_in_order_2/4这样的标识、以及src/AggregateFunctions/...的覆盖率关联都能在真实数据中落地验证。值得说明的数据分类边界记录在 .claude/skills/perf-comparison/scripts/test_perf_api.py 中is_changed abs(diff) changed_threshold and abs(diff) stat_thresholdis_unstable (not is_changed) and stat_threshold unstable_threshold方向direction slowdown if diff 0 else speedup。这个逻辑告诉我们“变化行”与“不稳定行”在分类层面就是互斥的两类——这正解释了判定规则为何反复强调不要用 unstable/high-noise 行去混充已变更行也印证了 verdict-rules 中“unstable test 不得因结果不合意而滥用”的约束。一份合格结论报告的最小结构把以上规则汇总成可执行的最小流程与 SKILL 的 Required report format 一致一份合格报告应包含Verdict 头结论标签七个之一 置信度等级high/medium/low已核对证据清单run/API URL、test/query/metric/arch、old/new/diff/threshold、重复 PR 运行结果、置信度 tier/reason、历史趋势含分位数、覆盖率/PR 关联、火焰图UI 查询页链接 top sample deltas或明确 not available、本地 perf.py若有Changed metrics 表清晰区分信号行与噪声/不确定行不让 unstable 行混入变更表结论理由说明为何当前有效证据支持该结论旧数据如何被取代推荐下一步动作no action / rerun performance CI / run local perf.py / inspect flamegraph hotspot / inspect PR code around covered files / bisect or targeted local validation。这套判定框架的本质是“证据加权”真实回归需要跨运行复现、历史无同类尖峰、相关指标一致、PR 关联合理等条件互相支撑而噪声、不稳定与证据不足也各有其必须展示的“反证数据”。无论数据来自 CI 仪表盘还是本地perf.py规则都要求把结论写成人可复核、机器可追溯的语句——这正是 ClickHouse 长期演进过程中控制性能回归工程实践的核心方法论。【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考