4. JQL进阶
基础 JQL 能解决“找出某个项目的未完成 Bug”这类问题,但研发效能度量真正需要的,往往是跨项目、跨时间、跨状态的复杂筛选。例如“过去 14 天内由当前用户参与、且被重新打开的 P1 缺陷”,或者“本季度已关闭但解决耗时超过 5 天的需求”。这类查询依赖四个进阶能力:逻辑组合、排序、历史搜索和动态日期函数。掌握它们,才能把仪表盘从静态快照变成随时间自动滚动的度量视图。
一、复杂条件:用 AND / OR / NOT 与括号控制逻辑
JQL 的逻辑运算符优先级是 NOT > AND > OR。这意味着 A OR B AND C 会被解析为 A OR (B AND C),而不是从左到右依次计算。一旦条件超过两个,强烈建议显式加括号,既避免歧义,也让后来维护仪表盘的人一眼看懂意图。
project IN (PAY, ORDER)
AND issuetype = Bug
AND priority IN (P1, P2)
AND status != Closed
AND (labels = "regression" OR labels = "customer-reported")
这里 IN 是多个等值的简写,!= 表示“不等于”,但要注意:status != Closed 在 Jira 中通常等价于 status NOT IN (Closed),语义是“状态不是 Closed”,而不是“状态字段为空”。如果某个问题没有状态值(极少见),它不会被 != 命中。另一个高频陷阱是 EMPTY 与 NULL:assignee IS EMPTY 表示未分配,assignee IS NOT EMPTY 表示已分配,不要用 assignee = "" 代替。
当需要匹配文本时,~ 是模糊匹配,!~ 是排除匹配。例如 summary ~ "timeout" 会命中摘要中包含 timeout 的问题。模糊匹配对中文分词支持有限,若字段是中文描述,建议优先用标签或自定义字段做精确筛选,而不是依赖全文模糊匹配。
二、排序:ORDER BY 决定“先看什么”
排序在度量场景中不只是美观问题。看板按优先级排序,能暴露高优积压;按更新时间倒序,能发现最近被频繁改动的“热点问题”;按创建时间正序,则适合做老化分析。JQL 的排序语法是 ORDER BY field ASC|DESC,可以多字段排序:
ORDER BY priority DESC, updated DESC, created ASC
注意 priority DESC 在 Jira 默认配置下会把 Highest 排在前面,因为优先级是按等级顺序定义的。如果团队自定义了优先级方案,排序结果会随方案变化,仪表盘迁移到另一个项目时可能“看起来变了”,这是常见困惑点。排序字段必须是 Jira 支持的排序字段,status、assignee、duedate、resolutiondate 都可用,但 labels 这类多值字段排序结果不稳定,不建议作为主排序键。
三、历史搜索:用 CHANGED 追踪状态与字段变化
历史搜索是 JQL 中最容易被低估的能力。它不查“当前值”,而是查“曾经发生过什么”。核心语法是 CHANGED:
status CHANGED FROM "In Progress" TO "Done"
AFTER "2024-01-01" BEFORE "2024-04-01"
这条查询找出在指定时间段内从“进行中”流转到“已完成”的问题,是计算周期吞吐量的基础。类似地,assignee CHANGED 可以追踪转派,priority CHANGED TO Highest 可以识别被临时升级的问题。CHANGED 还支持 BY 限定操作人:status CHANGED BY "zhangsan" TO Done,用于分析个人交付行为。
需要特别区分 CHANGED 与 WAS。status WAS "In Progress" 表示“曾经处于进行中”,不限定何时变化;status CHANGED TO "In Progress" 表示“发生过进入进行中的变更事件”。做“返工率”度量时,通常用 status CHANGED FROM Done TO "In Progress" 来识别被重新打开的问题,而不是用 status WAS Done,因为后者会把所有已完成过的问题都算进来。
四、动态日期函数:让仪表盘自动滚动
硬编码日期会让仪表盘第二天就过期。JQL 提供了一组相对时间函数,常用形式如下:
now():当前时刻,精确到分钟。startOfDay()、endOfDay():当天起止。startOfWeek()、endOfWeek():本周起止,默认周一为一周开始。startOfMonth()、endOfMonth():本月起止。startOfYear()、endOfYear():本年起止。
它们可以配合加减偏移量使用,单位是 w(周)、d(天)、h(小时)、m(分钟):
created >= -14d
updated >= startOfWeek()
resolutiondate >= startOfMonth() AND resolutiondate <= endOfMonth()
duedate < now() AND status != Done
第一条表示“最近 14 天内创建”,负号代表向过去偏移;第二条表示“本周内更新过”;第三条表示“本月内已解决”;第四条表示“已逾期且未完成”。这些写法让仪表盘无需人工维护日期,每天打开都是最新窗口。
startOfDay() 的“今天”可能与你本地日历不一致,做日报类度量时建议在查询说明中标注时区,或统一用 -24h 这类滚动窗口替代自然日边界。五、把四类能力组合成一条可用的度量查询
下面这条查询用于“本周内被重新打开、且当前仍未关闭的高优缺陷”,它同时用到了逻辑组合、历史搜索、动态日期和排序:
project IN (PAY, ORDER)
AND issuetype = Bug
AND priority IN (P1, P2)
AND status CHANGED FROM Done TO "In Progress"
AFTER startOfWeek()
AND status != Done
ORDER BY priority DESC, updated DESC
解读方式:先按项目与类型圈定范围,再用 CHANGED FROM Done TO "In Progress" 锁定“重新打开”这一历史事件,并用 AFTER startOfWeek() 限定在本周内发生,最后排除当前已关闭的问题,并按优先级和更新时间排序。结果列表就是本周需要重点复盘的返工缺陷。若把 startOfWeek() 换成 -7d,窗口就变成滚动 7 天,更适合每日站会使用。
最后提醒两个实践细节。第一,CHANGED 查询在大型实例上开销较高,如果仪表盘加载缓慢,可以先用项目、时间范围缩小候选集,再叠加历史条件。第二,动态日期函数的结果会随查询执行时刻变化,因此同一条 JQL 在不同时间运行可能返回不同数量的问题,这是预期行为,不是数据错误。把窗口定义写进仪表盘说明,团队对“本周”“本月”的口径才能保持一致。