# 从可观测面板回到原生证据

LLMS 索引： [llms.txt](/llms.txt)

---

Pigsty 的价值之一，是把 PostgreSQL、主机、连接池、代理、日志和 catalog 信息放进同一套时间与标签体系。面板擅长发现“何时、哪里、哪个查询族”异常；最终解释仍要能落回 exporter expression、PostgreSQL view、日志字段和计划 artifact。

## 8.6.1 用指标语义定位时间、实例与查询 {#item-8-6-1}

从宽到窄浏览，而不是从某张“慢查询”表直接猜根因：

```text
用户 SLI / 告警时间窗
  → cluster/service 是否整体异常
  → primary/replica/instance 差异
  → database/user/application/session
  → query family/queryid
  → wait/lock/plan/resource
  → 原生证据与受控实验
```

在当前 Pigsty dashboard 分类中，可按问题选择入口：

| 问题 | 参考 dashboard 家族 | 要带走的身份 |
|---|---|---|
| 全局/cluster 是否退化 | PGSQL Overview、Alert、Cluster | cluster、instance、role、UTC window |
| session、负载、锁 | PGSQL Activity、Session、Xacts、PGCAT Locks | database、application、state/wait、PID/session |
| query family | PGSQL Query、PGCAT Query、Database | db/user/queryid、calls/time/rows |
| 代理与连接池 | PGSQL Service、Proxy、PgBouncer | service route、pool/database/user |
| WAL/checkpoint/I/O | PGSQL Persist、Instance | instance timeline、counter/rate |
| 日志事件 | PGLOG Overview、Session | session/PID、SQLSTATE、timestamp |

这些名字是 Pigsty 的当前参考实现，不是永恒导航路径。若版本调整 dashboard，仍按“影响范围 → 实例 → 会话/query → 原生证据”的语义寻找。

打开任何图前，先读变量和 expression：

- 当前 cluster/service/instance/database/query 变量是什么；
- timezone 与 absolute start/end 是什么；
- unit 是 seconds、milliseconds、bytes、rows 还是 ratio；
- 原始 metric 是 counter、gauge 还是 histogram；
- `rate()`/`increase()` 窗口与 Grafana step 是多少；
- label 是否在 recording rule 中被聚合掉；
- primary role/failover 前后 instance identity 是否变化；
- `No data` 表示 0、未抓取、权限不足还是 exporter 错误。

颜色是展示规则，不是 PostgreSQL 语义。同一个红色可能代表固定阈值、动态 baseline 或只是主题配置；同一个“QPS”可能是 query counter rate、transaction rate 或 application request rate。下结论前保存 panel query、变量、时间范围与 datasource。

一个可靠的面板收敛过程：

1. 把用户事故窗口扩大到前后各一段，观察变化点；
2. 用同星期/相近流量窗口做 baseline；
3. 对比 primary/replica、受影响/未受影响实例；
4. 找到 database/user/application/queryid，而非只看 cluster 总量；
5. 同屏核对 calls/total/rows、wait/locks、CPU/I/O、pool queue；
6. 保存 absolute UTC window 和 query identity；
7. 用下一目的 SQL/log/plan 复核。

## 8.6.2 用 SQL、日志和计划复核面板判断 {#item-8-6-2}

面板提示 Lock wait 后，原生复核应至少得到一条边：

```sql
SELECT
    clock_timestamp() AT TIME ZONE 'UTC' AS captured_at_utc,
    pid,
    backend_start,
    datname,
    usename,
    application_name,
    state,
    wait_event_type,
    wait_event,
    pg_blocking_pids(pid) AS blocking_pids,
    xact_start,
    query_start,
    query_id
FROM pg_stat_activity
WHERE datname = :'database'
  AND state <> 'idle'
ORDER BY xact_start NULLS LAST;
```

面板提示某 query family 预算上升后，保存累计边界：

```sql
SELECT stats_reset
FROM pg_stat_statements_info;

SELECT
    userid, dbid, queryid, calls,
    total_exec_time, mean_exec_time, max_exec_time,
    rows, shared_blks_hit, shared_blks_read,
    temp_blks_written, wal_bytes,
    query
FROM pg_stat_statements
WHERE dbid = (
    SELECT oid FROM pg_database WHERE datname = :'database'
)
  AND queryid = :'queryid'::bigint;
```

若 panel 来自 Prometheus counter，优先导出事故窗口的 expression/result，而不是把当前累计 SQL 行与历史五分钟 rate 直接比较。记录：

```text
datasource + expression
absolute UTC range + step
all template variables
returned labels
counter reset/failover boundary
```

日志复核要能串到同一 session 或 query：

```text
timestamp
PID + session id/backend_start
database/user/application/client
SQLSTATE
duration
query/queryid
lock/temp/auto_explain context
```

计划复核则保存可机器比较的 JSON 与环境：

```sql
SELECT version();
SELECT name, setting, unit, source
FROM pg_settings
WHERE name IN (
    'plan_cache_mode',
    'work_mem',
    'random_page_cost',
    'effective_cache_size',
    'track_io_timing',
    'compute_query_id'
)
ORDER BY name;
```

再在安全环境使用代表参数执行：

```sql
EXPLAIN (ANALYZE, BUFFERS, WAL, SETTINGS, SUMMARY, FORMAT JSON)
SELECT ...;
```

如果生产语句正在 Lock/ClientWrite 等待，activity 与日志可能已经足够证明直接机制；不要为了补一张计划图冒险重跑。计划回答“executor 选择与处理了什么”，wait 回答“采样时为什么没前进”，两者互补。

面板提示“连接用满”也要回到边界：

- PostgreSQL session count 与 state；
- PgBouncer client/server active/waiting；
- application pool acquire duration；
- HAProxy backend/session；
- service route 与 primary role。

仅看到 PostgreSQL connections 接近上限，无法区分连接泄漏、长事务、pool 配太大、流量上升或 failover 重连风暴。

## 8.6.3 不把截图、颜色或当前点击路径当作知识 {#item-8-6-3}

截图可以证明“当时有人看见某个画面”，却通常缺少：

- panel expression 与数据源；
- 变量值与隐藏 filters；
- absolute start/end、timezone 和 step；
- unit、legend 聚合与 null handling；
- dashboard/version/commit；
- 原始样本与可重算结果；
- query/session identity；
- 图外的对照与反证。

因此证据包的优先级应是：

```text
1. 原始 SQL/CSV/JSON/log/Prometheus result
2. query/expression、变量、时间范围、版本与 source hash
3. 机器断言和人工解释
4. 截图作为定位/沟通附件
```

可长期保留的知识应写成语义：

```text
若 endpoint p99 退化：
  先锁定 absolute UTC window 和 event count；
  比较 cluster/instance/database/application/query scope；
  若 activity 显示 active + Lock，保存 blocker edge；
  若 active + ClientWrite 且 blockers 为空，转查结果消费；
  若无稳定 wait，再进入 plan/CPU/I/O 假设；
  所有结论回到原始 artifact。
```

而不是：

```text
打开左边第 3 个 dashboard，
点右上角红色方块，
再点第二行蓝色链接。
```

前一种写法能跨 Pigsty/Grafana 版本、主题和自定义 dashboard；后一种在下一次升级就失效。需要记录当前实现时，附上：

```text
Pigsty version
dashboard UID/title/revision
Grafana/Prometheus datasource
exporter and recording-rule source hash
PostgreSQL major/minor
```

面板本身也需要验证。常见故障包括 exporter down、scrape timeout、label 重命名、recording rule 计算错误、queryid 类型/符号处理、counter reset 未处理和 dashboard variable 选错实例。若面板与原生 SQL 矛盾，先核对口径与时间，不要自动相信“更漂亮”的一方。

本章的方法把 Pigsty 定位为可观测性工作台：

```text
Pigsty 快速收敛范围
  + PostgreSQL 证明机制
  + 应用/代理补全数据库外时间
  + 受控实验区分竞争解释
  + evidence bundle 供复核
```

下一节把这条链放进三个外观相似、修复方向完全不同的可复现实验。

## 参考资料

- [Pigsty：PostgreSQL Dashboards](https://pigsty.io/docs/pgsql/dashboard/)
- [PostgreSQL 18：Cumulative Statistics System](https://www.postgresql.org/docs/18/monitoring-stats.html)
- [PostgreSQL 18：pg_stat_statements](https://www.postgresql.org/docs/18/pgstatstatements.html)

---

[上一节：设计受控实验](../05/) · [返回本章目录](../) · [下一节：实战：三种“慢”只修真正瓶颈](../07/) ·
[查看全书目录](/toc/) · [查看索引中心](/indexes/)
