perf(db): 干掉列表/计数热路径上的「整表拼单聚合」,并给数据库留出 1 核
生产实测(2026-10-03,order_site):postgres 在 22.6 小时里烧了 12.2 CPU·小时 (均 0.54 核),却因 2 核配额累计被 cgroup 节流 9,337 秒;top 12 条语句占全部 DB CPU 的 69.4%,其中三条最热的就是「工单列表 / 计数 / 大厅候选集」。 一、查询形状(根因,不是缺索引) 接单大厅那条 COUNT 被调 71,539 次、均 103ms,EXPLAIN(ANALYZE,BUFFERS) 显示 82.8ms 里 35ms 花在「把整张 work_order_shares 聚合一遍再 join」: Index Only Scan rows=22,987 → GroupAggregate → 最终只用到 11 行;同一条 SQL 里 还有第二遍同样的全局聚合(filter_share_summary)。已改成按工单限定的关联子查询 (走 idx_work_order_shares_work_order): - buildWorkOrderWhere 的 excludeFilledSharing 过滤条件; - buildHallCandidateIdsSql 的 candidate_shares。 同参数实测:50.3ms → 2.1ms、35.9ms → 3.8ms、28.4ms → 1.8ms,buffer 10,145 → 187, 三种参数下结果逐行一致(11/11、5/5、11/11)。 有意保留 operational_share_summary 那一处全局聚合:全表统计(103,073 行)时 关联子查询要 103,073 次探测(330ms),一次聚合只要 55ms;已有用例钉住「只允许剩一处」。 二、容器与数据库参数 - POSTGRES_CPUS 2 → 3(4 核机器,同机其它容器实测只用 0.2-0.4 核且几乎不节流); - max_parallel_workers_per_gather 2 → 1(>1 时一条查询要 leader+2 worker=3 核,必撞配额); - checkpoint_timeout 300 → 900s、max_wal_size 1GB → 4GB(43 天累计 21,778 次检查点, sar 里就是每 20-40 分钟一轮写突发)。 三、迁移 092:热表 autovacuum 调参 可见性图陈旧导致 index-only scan 回表 5,580 次;work_orders/order_items/orders/ kuaishou_industry_vouchers/fulfillment_tasks 死元组 1.9 万-5.3 万、上次清理在前一天 甚至 9/29。把这些表的 scale_factor 0.2→0.05、analyze 0.1→0.02、cost_limit 200→800, 把「攒批猛扫」拆成「小步勤清」,并打开 5s 以上的 autovacuum 日志便于观测。 用例:新增 share-summary-scope.test.ts(钉住热路径不再出现整表聚合、只保留一处且有注释说明), env-documentation 白名单补 3 个新增部署变量。全量 599 通过,typecheck/lint/check:sql 通过。
This commit is contained in:
@@ -33,6 +33,9 @@ const DEPLOYMENT_ONLY_ENV_NAMES = [
|
||||
'POSTGRES_EFFECTIVE_CACHE_SIZE',
|
||||
'POSTGRES_WORK_MEM',
|
||||
'POSTGRES_MAINTENANCE_WORK_MEM',
|
||||
'POSTGRES_MAX_PARALLEL_WORKERS_PER_GATHER',
|
||||
'POSTGRES_CHECKPOINT_TIMEOUT',
|
||||
'POSTGRES_MAX_WAL_SIZE',
|
||||
'BACKEND_MEM_LIMIT',
|
||||
'BACKEND_CPUS',
|
||||
'BACKEND_NODE_OPTIONS',
|
||||
|
||||
Reference in New Issue
Block a user