# 最小 psql 生存卡

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

---

`psql` 同时是交互式终端、脚本执行器和 PostgreSQL 取证工具。本节只保留完成第 1 章所需的最小操作；变量、条件、服务文件、失败即停、批量输入输出和可靠脚本会在 ch02《psql 与可复现工作流》中系统展开。

先区分两种输入：

- 以反斜线开头的是 `psql` **元命令**，由客户端解释，通常不加分号；
- SQL 发送给 PostgreSQL 服务器，以分号结束，受事务与权限约束。

看到一个命令时先问“它由客户端还是服务器执行”，很多困惑会自动消失。

## 1.6.1 用 URI 连接，用 `\l`、`\dn`、`\d` 看对象 {#item-1-6-1}

使用连接 URI 可以让终端、应用驱动和文档共享同一种参数表达：

```bash
psql -X "$PG36_BOOTSTRAP_URL"
```

连接成功后，第一条元命令应是：

```text
\conninfo
```

它显示当前数据库、角色、主机或 socket、端口以及 TLS 等连接信息。随后按从大到小的顺序探索对象：

```text
\l+
\dn+
\d
\dt shop.*
\d+ shop.orders
\du+
\dx
```

它们依次列出数据库、当前数据库中的模式、可见关系、`shop` 模式中的表、指定对象详情、角色和已安装扩展；`+` 表示请求更详细的信息。对象尚未创建时，`\d+ shop.orders` 会明确报错。

`\d` 系列支持 `psql` 自己的对象模式匹配，不是 SQL 的 `LIKE`。例如 `shop.*` 表示模式 `shop` 下的对象；大小写与引号仍遵循 PostgreSQL 标识符规则。

元命令适合人类快速探索，系统目录查询适合明确筛选、保存和自动验证。两者应互相复核：

```sql
SELECT nspname
FROM pg_catalog.pg_namespace
ORDER BY nspname;
```

若 `\dn` 与查询结果看起来不同，先检查 `\dn` 是否过滤系统模式、用户是否有可见性权限，以及是否连接了同一个数据库，不要立即断言工具出错。

## 1.6.2 用 `\c` 切库，用 `-c` 与 `-f` 执行 {#item-1-6-2}

在交互会话中切换数据库：

```text
\c pg36_shop
\conninfo
```

`\c` 实际上会断开当前连接并建立新连接。未显式指定的主机、端口和角色通常沿用当前值；所以切换后必须再次执行 `\conninfo` 或上下文快照。若切换失败，`psql` 在交互模式下通常保留原连接，不要误以为已经进入目标库。

从 shell 执行一条 SQL：

```bash
psql -X "$PG36_BOOTSTRAP_URL" \
  -c 'SELECT current_database(), session_user, current_user;'
```

执行一个 SQL 文件：

```bash
psql -X "$PG36_BOOTSTRAP_URL" \
  -v ON_ERROR_STOP=1 \
  -f setup.sql
```

`-c` 适合短小、可见的一次性观察；`-f` 让错误消息包含文件与行号，适合可审查脚本。`ON_ERROR_STOP=1` 要求 `psql` 遇到脚本错误后停止，避免第一步失败后继续执行一串建立在错误前提上的语句。

不要把多行复杂 SQL 塞进 shell 的 `-c` 参数：shell 引号、SQL 引号和变量展开叠在一起，很容易产生与屏幕看起来不同的实际输入。复杂内容放入版本控制的 `.sql` 文件，并在执行前查看差异。

交互会话内也可以执行文件：

```text
\i setup.sql
```

但自动化与验收更适合从 shell 使用 `-f`，因为调用方可以读取退出码并保存标准输出、标准错误。

## 1.6.3 用 `\o` 或 `-A -t` 保存输出 {#item-1-6-3}

人读的表格与机器读的结果需要不同输出形式。

交互式保存随后产生的查询输出：

```text
\o pg36-connection.txt
SELECT current_database(), current_user, pg_is_in_recovery();
\o
```

第二个不带文件名的 `\o` 恢复到终端输出。忘记恢复时，后续查询“没有输出”往往只是仍在写文件。

从 shell 生成机器友好的单值或逐行结果：

```bash
psql -X "$PG36_BOOTSTRAP_URL" \
  -A -t \
  -v ON_ERROR_STOP=1 \
  -c 'SELECT current_database();'
```

- `-A` 使用不对齐输出，去掉表格边框；
- `-t` 只输出元组，去掉列名与行数提示；
- `-X` 避免个人 `psqlrc` 改写格式；
- `ON_ERROR_STOP` 让失败产生可判断的非成功退出。

若有多列，显式选择分隔符和空值表示，或者直接输出 JSON；不要让下游脚本解析为人类排版的表格：

```bash
psql -X "$PG36_BOOTSTRAP_URL" -A -t -c "
SELECT jsonb_build_object(
  'database', current_database(),
  'user', current_user,
  'in_recovery', pg_is_in_recovery()
);"
```

保存输出不等于保存证据上下文。文件旁还应记录采集时间、客户端入口、服务端版本和命令来源，否则一行 `false` 很快会失去解释价值。

## 1.6.4 用 `\q`、`Ctrl-C` 安全退出与中断 {#item-1-6-4}

正常退出：

```text
\q
```

如果正在输入但尚未发送一条 SQL，`Ctrl-C` 会清空当前查询缓冲区并回到提示符。可以先用 `\p` 查看缓冲区内容，用 `\r` 主动清空：

```text
\p
\r
```

前者显示尚未发送的查询，后者重置查询缓冲区。

如果服务器正在执行查询，`Ctrl-C` 会请求取消当前语句，而不是粗暴终止服务器进程。取消可能需要等待服务器到达可中断位置；网络中断时，客户端也未必能确认取消请求是否送达。

取消事务中的语句通常会让当前事务进入失败状态。此时后续 SQL 会收到“current transaction is aborted”，必须明确回滚：

```sql
ROLLBACK;
```

不要连续按键后在不知道状态的情况下继续操作。中断后立即执行：

```sql
SELECT
    current_database(),
    current_user,
    pg_is_in_recovery();
```

若查询能正常执行，说明连接仍可用且不在失败事务中；若连接已经断开，由 `psql` 明确重连后再重新采集上下文。

`Ctrl-Z` 只是把本地 `psql` 挂起，服务器连接和可能的事务仍然存在。它不是安全退出手段。遗留的 `idle in transaction` 会话可能长期持有快照和锁，是后续并发与膨胀问题的常见来源。

### 一张够用的生存卡

| 目标 | 命令 |
|---|---|
| 看当前连接 | `\conninfo` |
| 看数据库／模式／关系 | `\l+`、`\dn+`、`\d` |
| 看角色／扩展 | `\du+`、`\dx` |
| 切换数据库 | `\c <database>`，随后再次 `\conninfo` |
| 执行短 SQL／脚本 | shell 中 `-c`／`-f` |
| 脚本失败即停 | `-v ON_ERROR_STOP=1` |
| 保存交互输出 | `\o <file>`，完成后 `\o` |
| 输出机器可读单值 | `-X -A -t` |
| 取消／退出 | `Ctrl-C`／`\q` |

### 本节验收

从一个新终端完成以下闭环：

1. 用 URI 进入 `postgres`，执行 `\conninfo`；
2. 用 `\l+` 查看实例中的数据库，再用 `\c postgres` 明确重连；
3. 用 `\dn+` 找到 `public` 与系统模式，用系统目录查询复核；
4. 把当前数据库名以无表头单值形式保存到文件；
5. 运行 `SELECT pg_sleep(10);`，用一次 `Ctrl-C` 取消；
6. 执行上下文查询确认连接可用，最后用 `\q` 退出。

验收文件中数据库名必须精确为 `postgres`，且终端中没有遗留失败事务提示。1.7 创建 `pg36_shop` 后，再用同一组命令完成章级验收。

## 参考资料

- [PostgreSQL 18：psql](https://www.postgresql.org/docs/18/app-psql.html)
- [PostgreSQL 18：错误与消息字段](https://www.postgresql.org/docs/18/protocol-error-fields.html)

---

[上一节：Pigsty 的资源模型](../05/) · [返回本章目录](../) · [下一节：实战：建立 `pg36_shop` 地图与实验基线](../07/) ·
[查看全书目录](/toc/) · [查看索引中心](/indexes/)
