PG实战笔记 | 09 PostgreSQL psql客户端基本操作
上一篇我们完成了性能参数调优。这一篇,我们聊一个被很多人低估的工具:psql。它看起来只是一个黑底白字的命令行,但真正用熟之后,你会发现它比大多数图形化工具都高效------元命令、变量、脚本、监控,样样都能做。这一篇,我们把 psql 从"连接工具"升级为"运维利器"。
一、连接方式:不止 psql -U postgres
psql 支持多种连接方式,日常开发中最常用的是命令行参数:
bash
psql -h localhost -p 5432 -U postgres -d mydb
-h:主机地址-p:端口,默认 5432-U:用户名-d:数据库名
但在复杂环境中,参数多了容易记错。更推荐使用 连接字符串:
bash
# URI 格式
psql "postgresql://postgres:password@localhost:5432/mydb?sslmode=require"
# conninfo 格式
psql "host=localhost port=5432 dbname=mydb user=postgres"
URI 格式的通用结构是 postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]。连接字符串支持附带 sslmode 等参数,适合远程连接和生产环境。
密码管理的最佳实践: 不要在命令行中直接写密码(会出现在 ps aux 中),也不要依赖 PGPASSWORD 环境变量。使用 ~/.pgpass 文件------psql 会自动读取,权限设为 600,安全且无感。
二、信息查询:\d 系列是日常使用频率最高的命令
psql 的元命令以反斜杠 \ 开头,其中最核心的是 \d 系列。掌握这些命令,你可以在不写任何 SQL 的情况下摸清数据库全貌。
列出所有数据库
sql
\l -- 列出所有数据库
\l+ -- 附带大小、表空间、描述
\l 是连接后第一个该执行的命令,确认自己连到了正确的数据库。
切换数据库
sql
\c mydb -- 切换到 mydb
\c mydb postgres -- 以 postgres 用户切换到 mydb
查看表结构
sql
\d users -- 查看 users 表的列、索引、约束
\d+ users -- 附带注释和磁盘大小
\d 不仅显示列名和类型,还会显示索引、主键、外键、触发器、访问权限------基本上是这个表的完整画像。
按对象类型列出
\d 系列有一套完整的变体,按对象类型过滤:
| 命令 | 作用 |
|---|---|
\dt |
仅表 |
\di |
仅索引 |
\dv |
仅视图 |
\ds |
仅序列 |
\dn |
模式 |
\du / \dg |
角色 |
\df |
函数 |
\dx |
已安装扩展 |
\dT |
数据类型 |
\db |
表空间 |
这些命令都支持模式匹配。\dt int\* 会显示所有以 int 开头的表;\dt *.* 则列出所有模式下的表。
查看配置参数(PG 16+)
sql
\dconfig -- 仅显示非默认值的参数
\dconfig shared* -- 显示所有以 shared 开头的参数
\dconfig * -- 显示全部参数
\dconfig+ work_mem -- 附带类型、上下文、权限信息
\dconfig 是 PostgreSQL 16 引入的命令,比 SHOW 更灵活------支持通配符模式,不用精确记住参数名。
三、格式化与效率:让输出更易读,让操作更快
\timing:显示执行耗时
sql
\timing -- 切换开关
\timing on -- 开启
\timing off -- 关闭
开启后,每条 SQL 执行完毕都会在结果下方显示耗时(毫秒级)。这是日常开发中最实用的元命令之一------你能立刻感受到索引是否生效、查询是否变慢。
\x:扩展显示,宽表救星
sql
\x -- 切换开关
\x auto -- 自动模式:窄结果用表格,宽结果用扩展格式
当查询返回的列很多时,默认的表格输出会折行得惨不忍睹。\x 把每行数据转成"列名 | 值"的纵向格式,一条记录一目了然。\x auto 是更聪明的选择,psql 会根据结果宽度自动决定是否使用扩展格式。
\pset null:让 NULL 可见
默认情况下,psql 无法区分 NULL 和空字符串。设置一个可见的 NULL 标记:
sql
\pset null '(null)'
之后所有 NULL 值都会显示为 (null),空字符串则显示为空白。
\watch:重复执行查询
sql
\watch 5 -- 每 5 秒执行一次上一条查询
\watch i=5 c=10 -- 每 5 秒执行,共执行 10 次
\watch 重复执行当前查询缓冲区中的查询,默认间隔 2 秒。它和 \timing 配合,可以在 psql 里搭建一个简易的监控面板:
sql
SELECT count(*) FROM orders WHERE status = 'pending';
\timing on
\watch 10
每 10 秒刷新一次待处理订单数,同时显示查询耗时。PostgreSQL 16 起支持 \watch 0(无延迟) ,但需注意客户端 CPU 消耗。
\e:用编辑器写 SQL
sql
\e -- 用 $EDITOR 打开上一条查询进行编辑
\e filename.sql -- 编辑指定文件
在编辑器里写复杂的多表 JOIN 或 CTE,比在 psql 里一行行敲高效得多。保存退出后,psql 会自动执行编辑后的 SQL。
\s:查看命令历史
sql
\s -- 显示历史命令
\s /tmp/history -- 保存到文件
\s 显示当前会话的命令历史,方便回顾刚才执行了哪些操作。配合 ~/.psqlrc 配置文件,可以在每次启动 psql 时自动设置常用参数,比如 \timing on、\pset null '(null)'、\x auto。
四、数据导入导出:\copy 与 COPY 的本质区别
这是 psql 中最容易被混淆的知识点。
COPY 是 SQL 命令,在服务器端 执行,读写的是服务器文件系统上的文件,权限取决于 postgres 进程的操作系统用户。
\copy 是 psql 元命令,在客户端 执行,读写的是你本地机器上的文件,权限取决于你当前的用户。
换句话说:如果你在本地机器上有一个 CSV 文件要导入远程数据库,必须用 \copy;如果你要导出数据到服务器上的某个路径,用 COPY。
\copy 的常用形式
sql
-- 导出查询结果到本地 CSV
\copy (SELECT * FROM users WHERE created_at > '2026-01-01') TO '/tmp/users.csv' WITH CSV HEADER
-- 从本地 CSV 导入
\copy users FROM '/tmp/users.csv' WITH CSV HEADER
\copy 会自动把数据通过客户端/服务器连接传输,底层调用的是 COPY FROM STDIN 或 COPY TO STDOUT。注意:由于数据要经过客户端中转,\copy 的效率略低于服务器端 COPY,但对于日常导入导出完全够用。
五、性能排查:psql 能做的比你想的多
psql 不只是执行 SQL 的地方,它也是排查性能问题的第一现场。
查看当前活跃查询
sql
SELECT pid, usename, application_name,
now() - query_start AS duration,
state, wait_event_type, wait_event, query
FROM pg_stat_activity
WHERE state != 'idle'
AND pid <> pg_backend_pid()
ORDER BY duration DESC;
pg_stat_activity 是排查阻塞、长事务、连接泄漏的起点。重点关注 state 为 active 且 duration 很大的查询,以及 state 为 idle in transaction 的会话------后者往往意味着应用忘记提交或回滚,持续持有锁。
查看锁等待
sql
SELECT blocked_locks.pid AS blocked_pid,
blocking_locks.pid AS blocking_pid,
blocked_activity.query AS blocked_query,
blocking_activity.query AS blocking_query
FROM pg_locks blocked_locks
JOIN pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
AND blocking_locks.pid != blocked_locks.pid
JOIN pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;
这个查询直接告诉你谁在阻塞谁,以及双方在执行什么 SQL。
查看最耗时的 SQL(需 pg_stat_statements)
sql
SELECT query, calls, total_exec_time, mean_exec_time, rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
pg_stat_statements 是性能排查的必备扩展。按 total_exec_time 排序,能找到"总耗时最高"的 SQL;按 mean_exec_time 排序,能找到"单次最慢"的 SQL。两种维度各有用途:前者适合优化高频查询,后者适合优化单点慢查询。
用 \watch 实时监控
sql
SELECT count(*) FROM pg_stat_activity WHERE state = 'active';
\watch 5
一个极简的实时监控:每 5 秒刷新一次活跃查询数。如果这个数字持续偏高,说明数据库正在承受较大压力。
六、总结
psql 的核心能力可以归纳为五组:
| 类别 | 关键命令 | 用途 |
|---|---|---|
| 连接 | 连接字符串、~/.pgpass |
安全、灵活地连接 |
| 信息查询 | \l、\c、\d、\dt、\di、\dconfig |
摸清数据库全貌 |
| 格式化 | \timing、\x、\pset null |
提升可读性 |
| 效率 | \e、\s、\watch |
加速日常操作 |
| 数据与排查 | \copy、pg_stat_activity、pg_stat_statements |
导入导出与性能诊断 |
一句话:psql 不是"没有图形界面所以将就用",而是"因为没有图形界面所以更快"。 把 ~/.psqlrc 配好,把 \timing、\x auto、\pset null 设成默认,你会发现命令行才是 PostgreSQL 最舒服的工作方式。
下一篇,我们聊聊 pgAdmin 和 DBeaver:图形化工具适合什么场景,怎么用它们管理数据库、查看执行计划,以及如何避免在生产环境误操作。
思考题:
你平时用 psql 还是图形化工具?有没有用 \watch 做过实时监控,或者用 pg_stat_activity 定位过阻塞?欢迎在评论区分享你的 psql 使用习惯。
