perf(worker): 「仅问题单」检索短路,从 pending 表反查而非枚举可见集
问题单页签原先走完整派生表达式:为该打手枚举全部可见单并逐行求值 嵌套 CASE + pending EXISTS(重打手 8,586 单 × 逐行探测 ≈ 233MB 缓冲读), 而问题单结果通常为空——生产实测 worker_order_cancel_requests 与 worker_order_feedbacks 的 pending 行数当前均为 0。 短路形状: wo.status = 'problem' OR (基础状态 = 'in_progress' AND wo.id IN (两张 pending 表反查)) - 左臂必须写成 sargable 的 wo.status = 'problem':基础状态等于 'problem' 当且仅当 wo.status = 'problem'(派生分支没有 problem 映射); - 反查走迁移 058 的两张 pending 专用索引,实测 8 个块; - 仅当请求状态"只含 problem"时短路,混合状态仍走完整表达式(结果集完整性); - 顺带把 workerOrderStatusExpression 拆出 workerOrderBaseStatusExpression 复用。 生产 EXPLAIN(worker=7):29,851 块 / 267ms → 13,387 块 / 118ms。
This commit is contained in:
@@ -173,6 +173,34 @@ test('普通关键词仍然走 trgm 表达式模糊搜索', () => {
|
||||
assert.deepEqual(query.params, ['%指挥官密钥%'])
|
||||
})
|
||||
|
||||
test('「仅问题单」检索走短路分支,从 pending 表反查而非枚举可见集', () => {
|
||||
const query = buildWorkOrderWhere({ workerSharingId: 7, statuses: ['problem'] })
|
||||
|
||||
// 短路形状:sargable 的直查 + 从两张极小的 pending 表反查
|
||||
assert.match(query.whereClause, /wo\.status = 'problem'/)
|
||||
assert.match(query.whereClause, /FROM worker_order_cancel_requests/)
|
||||
assert.match(query.whereClause, /FROM worker_order_feedbacks/)
|
||||
assert.match(query.whereClause, /status = 'pending'/)
|
||||
// 不得再生成完整派生表达式(那会强制对该打手全部可见单逐行求值)
|
||||
assert.doesNotMatch(query.whereClause, /THEN 'problem'\s+ELSE CASE/)
|
||||
// 第一个 7 来自 worker_visible 连接,第二个 7 是短路分支的打手 id
|
||||
assert.deepEqual(query.params, [7, 7])
|
||||
})
|
||||
|
||||
test('问题单与其它状态混合时不得短路,必须走完整派生表达式', () => {
|
||||
const query = buildWorkOrderWhere({ workerSharingId: 7, statuses: ['problem', 'in_progress'] })
|
||||
|
||||
assert.match(query.whereClause, /= ANY\(\$\d+::text\[\]\)/, '混合状态必须用完整表达式')
|
||||
// 完整表达式的 EXISTS 里也会出现这两张表,用短路分支独有的「SELECT work_order_id + UNION」
|
||||
// 形状来判别,确保混合状态没有误入短路
|
||||
assert.doesNotMatch(
|
||||
query.whereClause,
|
||||
/SELECT work_order_id\s+FROM worker_order_cancel_requests/,
|
||||
'混合状态误入短路分支会导致结果集不完整',
|
||||
)
|
||||
assert.deepEqual(query.params, [7, ['problem', 'in_progress']])
|
||||
})
|
||||
|
||||
test('单号检索分支不得回退成裸列模糊匹配(源码级防退化守卫)', async () => {
|
||||
const { readFile } = await import('node:fs/promises')
|
||||
const src = await readFile(
|
||||
|
||||
@@ -192,12 +192,19 @@ function buildRelatedWorkOrderLookupFilter(
|
||||
}
|
||||
|
||||
/**
|
||||
* 打手订单个人状态:拼单按个人份额状态计算。
|
||||
* 传入 workerId 时,代练中但存在待审核取消申请或未处理反馈的订单归入问题单,
|
||||
* 客服驳回/解决后自动回到代练中(计算型归类,无状态迁移)。
|
||||
* 是否为「仅问题单」筛选。前端问题单页签固定传单个 problem;
|
||||
* 一旦混入其它状态就必须走完整派生表达式,不能短路。
|
||||
*/
|
||||
export function workerOrderStatusExpression(workerId = 0, workerShareAlias = 'worker_share') {
|
||||
const baseExpression = `CASE
|
||||
function isProblemOnlyStatusFilter(statuses: string[]): boolean {
|
||||
return statuses.length === 1 && statuses[0] === 'problem'
|
||||
}
|
||||
|
||||
/**
|
||||
* 打手订单基础状态:拼单按个人份额状态计算(不含"问题单"派生)。
|
||||
* 拆出来是因为「仅问题单」检索可以用它做短路,不必派生完整表达式。
|
||||
*/
|
||||
export function workerOrderBaseStatusExpression(workerShareAlias = 'worker_share') {
|
||||
return `CASE
|
||||
WHEN wo.status IN ('accepted', 'cancelled', 'problem') THEN wo.status
|
||||
ELSE COALESCE(CASE ${workerShareAlias}.status
|
||||
WHEN 'joined' THEN 'in_progress'
|
||||
@@ -207,6 +214,15 @@ export function workerOrderStatusExpression(workerId = 0, workerShareAlias = 'wo
|
||||
ELSE wo.status
|
||||
END, wo.status)
|
||||
END`
|
||||
}
|
||||
|
||||
/**
|
||||
* 打手订单个人状态:拼单按个人份额状态计算。
|
||||
* 传入 workerId 时,代练中但存在待审核取消申请或未处理反馈的订单归入问题单,
|
||||
* 客服驳回/解决后自动回到代练中(计算型归类,无状态迁移)。
|
||||
*/
|
||||
export function workerOrderStatusExpression(workerId = 0, workerShareAlias = 'worker_share') {
|
||||
const baseExpression = workerOrderBaseStatusExpression(workerShareAlias)
|
||||
const normalizedWorkerId = Math.max(0, Math.floor(Number(workerId) || 0))
|
||||
if (normalizedWorkerId <= 0) return baseExpression
|
||||
const pendingHandlingExists = `(
|
||||
@@ -963,16 +979,45 @@ export function buildWorkOrderWhere({
|
||||
filters.push(`(${vipEvidencePendingWhere})`)
|
||||
}
|
||||
} else if (normalizedStatuses.length > 0) {
|
||||
params.push(normalizedStatuses)
|
||||
const statusesPlaceholder = `$${params.length}`
|
||||
if (workerSharingId) {
|
||||
filters.push(
|
||||
`${workerOrderStatusExpression(workerSharingId)} = ANY(${statusesPlaceholder}::text[])`,
|
||||
)
|
||||
if (workerSharingId && isProblemOnlyStatusFilter(normalizedStatuses)) {
|
||||
// 「仅问题单」短路:问题单 = wo.status 直接是 problem,或 进行中 且挂着
|
||||
// 待审核取消申请/未处理反馈。两条 pending 表极小(生产实测常为 0 行),
|
||||
// 从它们出发反查,避免为了一个通常为空的结果枚举该打手全部可见单再逐行求值
|
||||
// 完整 CASE(重打手 8,586 单 × 逐行探测 ≈ 233MB 缓冲读)。
|
||||
// 注意左臂必须写成 sargable 的 wo.status = 'problem':完整表达式里
|
||||
// 基础状态等于 'problem' 当且仅当 wo.status = 'problem'(派生分支没有 problem 映射)。
|
||||
params.push(workerSharingId)
|
||||
const workerIdPlaceholder = `$${params.length}`
|
||||
const baseExpression = workerOrderBaseStatusExpression('worker_share')
|
||||
filters.push(`(
|
||||
wo.status = 'problem'
|
||||
OR (
|
||||
${baseExpression} = 'in_progress'
|
||||
AND wo.id IN (
|
||||
SELECT work_order_id
|
||||
FROM worker_order_cancel_requests
|
||||
WHERE worker_id = ${workerIdPlaceholder}
|
||||
AND status = 'pending'
|
||||
UNION
|
||||
SELECT work_order_id
|
||||
FROM worker_order_feedbacks
|
||||
WHERE worker_id = ${workerIdPlaceholder}
|
||||
AND status = 'pending'
|
||||
)
|
||||
)
|
||||
)`)
|
||||
} else {
|
||||
filters.push(
|
||||
`${useOperationalStatus ? adminOperationalStatusExpression('wo', 'operational_share_summary') : 'wo.status'} = ANY(${statusesPlaceholder}::text[])`,
|
||||
)
|
||||
params.push(normalizedStatuses)
|
||||
const statusesPlaceholder = `$${params.length}`
|
||||
if (workerSharingId) {
|
||||
filters.push(
|
||||
`${workerOrderStatusExpression(workerSharingId)} = ANY(${statusesPlaceholder}::text[])`,
|
||||
)
|
||||
} else {
|
||||
filters.push(
|
||||
`${useOperationalStatus ? adminOperationalStatusExpression('wo', 'operational_share_summary') : 'wo.status'} = ANY(${statusesPlaceholder}::text[])`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (workOrderId) {
|
||||
|
||||
Reference in New Issue
Block a user