加载中...

加载中...

psql 是 PostgreSQL 官方命令行客户端,也是最能体现 PG 风格的入口。它的**元命令(meta-commands)**系统比多数数据库的命令行工具都好用——\d 家族看结构、\x 看宽表、\gset 存变量、\copy 传数据。本文聚焦这个工具本身。SQL 语法见 SQL 命令使用教程,PG 数据库本身见 PostgreSQL 使用全面指南

一、启动与连接

1.1 基本方式

psql                                      # 用当前系统用户连本地默认库
psql -U app -d sales_db                   # 指定用户和库
psql -h db.example.com -p 5432 -U app -d sales_db

1.2 参数速查

参数含义示例
-U用户名-U app
-d数据库名-d sales_db
-h主机(不写走 Unix socket)-h db.example.com
-p端口(默认 5432)-p 6432
-W强制提示输入密码-W
-c执行一条命令后退出-c "SELECT 1"
-f执行 SQL 文件-f setup.sql
-l列出所有数据库-l
-v设置变量-v tbl=users
-A无对齐输出(便于脚本解析)-A
-t只输出行,不带表头和边框-t
--csv直接输出 CSV--csv

1.3 URI 连接串

psql "postgresql://app:secret@db.example.com:5432/sales_db?sslmode=require"

URI 形式在脚本和 ORM 配置里很常见,附加参数(sslmodeconnect_timeout)直接写在 query string 里。

1.4 免密登录:.pgpass

在命令行写密码既不方便也不安全。PG 的标准做法是 ~/.pgpass

# 格式:hostname:port:database:username:password
cat > ~/.pgpass <<'EOF'
db.example.com:5432:sales_db:app:your_password
*:*:*:app:fallback_password
EOF
chmod 600 ~/.pgpass      # 权限必须是 600,否则 psql 会忽略它

之后 psql -h db.example.com -U app -d sales_db 就直接连上,无需输密码。* 是通配。

注意 chmod 600 不是可选项。权限过宽时 psql静默忽略这个文件,你会以为是密码错了。

二、元命令:psql 的精华

元命令以 \ 开头,是 psql 客户端自己的指令,不是 SQL——不能写进 .sql 文件用 -f 执行,也不能通过驱动调用。

2.1 \d 家族(看结构)

命令作用
\d列出所有表、视图、序列
\d table看某张表的详细结构(列、索引、约束、外键)
\d+ table同上,附存储大小和描述
\dt只看表
\dv只看视图
\di只看索引
\ds只看序列
\df只看函数
\dn列出所有 schema
\dS包含系统表
\dp table查看权限(等价 \z
\d products
                               Table "public.products"
 Column |     Type      | Collation | Nullable |               Default
--------+---------------+-----------+----------+--------------------------------------
 id     | integer       |           | not null | nextval('products_id_seq'::regclass)
 name   | text          |           |          |
 price  | numeric(10,2) |           |          |
Indexes:
    "products_pkey" PRIMARY KEY, btree (id)

\d table 的输出把列定义、索引、外键一次给全,比 information_schema 查询快得多。

2.2 数据库与角色

\l              -- 列出所有数据库(等价 \list)
\c dbname       -- 切换数据库(等价 \connect)
\c dbname otheruser  -- 切换数据库同时切用户
\du             -- 列出所有角色(用户)
\du+            -- 附角色描述
\conninfo       -- 显示当前连接信息
\conninfo
You are connected to database "postgres" as user "postgres" via socket in
"/var/run/postgresql" at port "5432".

2.3 帮助系统

\?              -- 所有元命令的帮助
\h              -- SQL 命令列表
\h CREATE TABLE -- 查看某条 SQL 的语法
\h CREATE INDEX

\?\h离线速查,比切浏览器查文档快。忘了某个选项就敲 \?

三、输出与显示控制

3.1 \x:宽表救星

\x auto
SELECT * FROM big_wide_table;

\x(expanded display)把结果从"一行多列"转成"一列多行":

-[ RECORD 1 ]---
id    | 1
name  | 张三
price | 9.99

\x auto推荐设置——列多到放不下时自动切换扩展模式,列少时保持表格。\x 单独用是强制开启,再敲一次关掉。

3.2 \pset:格式化细节

\pset null '[NULL]'      -- 空值显示为 [NULL](默认是空白,容易和空字符串混淆)
\pset border 2           -- 边框样式(0/1/2)
\pset format csv         -- 输出格式(aligned/unaligned/csv/html/latex/json)
\pset pager off          -- 关闭分页器(结果直接刷屏,配合 \o 写文件)
\pset expanded auto      -- 等价 \x auto

\pset null '[NULL]' 建议写进 .psqlrc——NULL 和空串在输出里长得一样,是排查数据问题的常见干扰。

3.3 \timing

\timing on
SELECT count(*) FROM big_table;
 count
--------
 1000000
(1 row)

Time: 123.456 ms

开了之后每条语句后面都会显示耗时,调试慢查询时第一件该做的事

3.4 \watch:周期执行

SELECT count(*) FROM pg_stat_activity WHERE state = 'active';
\watch 2

每 2 秒重跑一次上一条查询(Ctrl+C 退出)。监控连接数、队列长度这类实时指标很好用,比反复按上箭头敲回车优雅。

3.5 输出重定向 \o

\o /tmp/report.txt
SELECT * FROM sales_summary;
SELECT * FROM top_customers;
\o                    -- 不带参数表示恢复输出到终端

\o 之后所有查询结果都写入文件,直到用不带参数的 \o 关闭。

四、查询缓冲与编辑

psql 维护一个"查询缓冲"(query buffer),你敲的内容先进缓冲,遇到 ; 才发送执行。

命令作用
\p打印当前缓冲内容(检查有没有敲错)
\e$EDITOR 打开编辑器编辑当前缓冲
\r清空缓冲
\g执行缓冲内容
\gx执行缓冲,并以扩展格式输出
\gset执行并把结果存成变量(见 §5.1)
\g filename执行并写入文件

多行查询直接敲就行——psql 会一直等 ;

SELECT
    first_name,
    last_name
FROM employees
WHERE hire_date > '2020-01-01'
;                          -- 分号结束并执行

常见误解:不需要"单独一行分号来结束多行模式"——分号只是语句终止符,跟在查询末尾即可(上面写成单独一行只是为了排版)。另外 \set PROMPT1 ...改提示符外观,和"多行模式"没有任何关系。

五、变量与脚本化

5.1 变量

\set tbl employees
SELECT count(*) FROM :tbl;

\set minimum 100
SELECT * FROM products WHERE price > :minimum;

把查询结果存进变量\gset)——做后续判断时很有用:

SELECT count(*) AS cnt FROM products \gset
\echo '产品数量: ' :cnt
产品数量:  2

5.2 脚本化执行

psql -d sales_db -f setup.sql -v ON_ERROR_STOP=1
  • -f file:执行文件
  • -v ON_ERROR_STOP=1遇错立即停止。默认 psql 会忽略错误继续执行——批量脚本里这往往是灾难,务必开启
  • -v tbl=users:从命令行传变量进去

脚本里判断执行结果

if psql -d sales_db -v ON_ERROR_STOP=1 -f migrate.sql; then
    echo "迁移成功"
else
    echo "迁移失败,退出码 $?"
    exit 1
fi

psql 的退出码:0 成功,1 致命错误(连不上等),2 会话正常结束但 ON_ERROR_STOP 触发过,3 脚本出错。

5.3 输出格式适合脚本

# 无对齐 + 无表头,便于 awk/cut 处理
psql -A -t -d sales_db -c "SELECT id, name FROM products"

# 直接输出 CSV
psql --csv -d sales_db -c "SELECT id, name FROM products" > products.csv

六、导入导出

6.1 \copyCOPY 的区别(重要)

这是最容易混淆的一对:

COPY\copy
类型SQL 命令psql 元命令
文件位置服务器客户端(执行 psql 的机器)
权限需要超级用户或 pg_read_server_files用当前数据库用户权限即可
服务端可用✅(任何 SQL 客户端)❌(只在 psql 里)
-- \copy:文件在本地机器
\copy (SELECT * FROM users) TO '/tmp/users.csv' CSV HEADER
\copy users FROM '/tmp/users.csv' CSV HEADER
-- COPY:文件在数据库服务器上
COPY employees FROM '/var/lib/postgresql/employees.csv' DELIMITER ',' CSV HEADER;

日常用 \copy——你不一定能在数据库服务器上放文件,也不一定有超级用户权限。

6.2 pg_dump 备份

# 纯文本 SQL(可读,但恢复慢)
pg_dump -U app sales_db > sales_db.sql

# 自定义格式(推荐:压缩 + 支持并行恢复 + 选择性恢复)
pg_dump -U app -Fc sales_db > sales_db.dump

# 只导出结构 / 只导出数据
pg_dump -U app --schema-only sales_db > schema.sql
pg_dump -U app --data-only sales_db > data.sql

# 只导出某张表
pg_dump -U app -t products sales_db > products.sql

# 并行导出(大库提速,-Fd 目录格式才支持 -j)
pg_dump -U app -Fd -j 4 sales_db -f /backup/sales_db_dir

6.3 恢复

# 纯文本:用 psql 执行
psql -U app -d sales_db -f sales_db.sql

# 自定义/目录格式:用 pg_restore
pg_restore -U app -d sales_db sales_db.dump
pg_restore -U app -d sales_db -j 4 /backup/sales_db_dir   # 并行恢复

# 只恢复某张表
pg_restore -U app -d sales_db -t products sales_db.dump

-Fc 自定义格式比纯 SQL 文本更值得用:体积更小、支持并行恢复、能选择性恢复单表,纯文本格式这三点都做不到。

七、.psqlrc 定制

把常用设置写进 ~/.psqlrc,每次启动自动生效:

-- 空值显示
\pset null '[NULL]'

-- 宽表自动扩展
\x auto

-- 显示执行时间
\timing on

-- 历史文件按数据库分开
\set HISTFILE ~/.psql_history-:DBNAME
\set HISTSIZE 5000

-- 出错即停(交互式下建议关掉,脚本里建议开)
\set ON_ERROR_STOP off

-- 常用查询的快捷方式(用 \set + :var)
\set active 'SELECT pid, state, query FROM pg_stat_activity WHERE state = $q$active$q$;'

$q$...$q$ 是 PG 的 dollar-quoting,可以避免字符串里的引号冲突。写长 SQL 进 .psqlrc 时很实用。

八、性能诊断

8.1 执行计划

EXPLAIN SELECT * FROM products WHERE price > 10;
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM products WHERE price > 10;

(ANALYZE, BUFFERS) 是调优标配ANALYZE 实际执行并给出各节点真实耗时和行数,BUFFERS 给出缓存命中情况(shared hit vs shared read——read 多说明要从磁盘读)。

看执行计划时重点找:

  • Seq Scan + 大表:全表扫描,考虑加索引
  • rows= 预估与实际差很多:统计信息过期,跑 ANALYZE table
  • Nested Loop 出现在大表上:可能是 JOIN 方式选错了
  • shared read 很高:缓存不足或索引没命中

8.2 当前活动

-- 正在运行的查询
SELECT pid, usename, state, wait_event_type, wait_event,
       now() - query_start AS duration, left(query, 60) AS q
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY duration DESC;

-- 连接数统计
SELECT usename, state, count(*) FROM pg_stat_activity GROUP BY usename, state;

杀掉一个卡住的查询

SELECT pg_cancel_backend(12345);       -- 温和取消(等价 Ctrl+C)
SELECT pg_terminate_backend(12345);    -- 强制断开连接

8.3 表与索引统计

-- 表的增删改查次数、顺序扫描次数
SELECT relname, seq_scan, idx_scan, n_live_tup, n_dead_tup
FROM pg_stat_user_tables
ORDER BY seq_scan DESC;

-- 索引使用情况(idx_scan 为 0 的索引可能是多余的)
SELECT relname, indexrelname, idx_scan, idx_tup_read
FROM pg_stat_user_indexes
ORDER BY idx_scan;

seq_scan 高而 idx_scan 低,说明索引没被用上;n_dead_tup 高说明需要 VACUUM

8.4 表空间占用

-- 单表大小
SELECT pg_size_pretty(pg_total_relation_size('products'));

-- 各表大小排行
SELECT relname,
       pg_size_pretty(pg_total_relation_size(relid)) AS total_size
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;

-- 当前数据库大小
SELECT pg_size_pretty(pg_database_size(current_database()));

九、维护操作

VACUUM products;                 -- 回收死元组空间(不锁表,可并发)
VACUUM ANALYZE products;         -- 回收 + 更新统计信息
VACUUM FULL products;            -- 彻底整理并归还空间给操作系统(⚠️ 会锁表!)
ANALYZE products;                -- 只更新统计信息
REINDEX TABLE products;          -- 重建索引(索引膨胀时用)
REINDEX TABLE CONCURRENTLY products;  -- 并发重建,不阻塞写(更慢)

VACUUM FULL 会持有排他锁,期间该表读写全部阻塞。大表上执行可能锁几分钟甚至更久。日常维护用普通 VACUUM(或依赖 autovacuum)即可;确实需要回收磁盘空间时,考虑 pg_repack 扩展做在线整理。

十、故障排查

10.1 认证失败

psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed:
FATAL:  password authentication failed for user "app"

排查顺序:

  1. 密码是否正确(注意 .pgpass 是否被权限问题忽略了)
  2. pg_hba.conf 是否允许该 host/database/user 组合,以及要求的认证方式(peer/md5/scram-sha-256
  3. 改完 pg_hba.confSELECT pg_reload_conf(); 或重启才生效
# 看当前的 hba 规则
psql -c "SHOW hba_file;"

10.2 常见错误

报错含义处理
password authentication failed密码/认证配置问题见上
no pg_hba.conf entry for host该主机未被允许pg_hba.conf 加规则
FATAL: database "x" does not exist库名错\l 确认
permission denied for table x无权限GRANT 授权
relation "x" does not exist表不存在,或 search_path 没包含该 schema\dt schema.* 确认
deadlock detected死锁,PG 已回滚一方重试;检查加锁顺序
could not serialize access可串行化隔离下冲突重试事务
too many connections连接数满pg_stat_activity,考虑连接池

relation does not exist 里最常见的隐性原因是 search_path——表建在别的 schema 下,而 search_path 只有 "$user", public

SHOW search_path;
SET search_path TO myschema, public;

10.3 权限问题

-- 看某张表的权限
\dp products

-- 授权
GRANT SELECT, INSERT, UPDATE ON products TO app;
GRANT USAGE ON SCHEMA public TO app;             -- 访问 schema 本身也要授权
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO app;   -- 自增序列要单独授

PG 的权限模型里,USAGE ON SCHEMA 和序列权限是常被忘记的两项。只授表权限、不授 schema 和序列权限时,会出现"能 SELECT 但 INSERT 报 nextval 权限不足"的怪现象。

十一、实用技巧

  1. Tab 补全:连表名、列名、schema 都能补全,比手敲快且不易错

  2. 上下箭头:浏览历史命令(历史存在 ~/.psql_history

  3. \! 执行 shell 命令

    \! ls -l /backups
    \! df -h

    注意\! 后面跟的是系统命令,不是"历史行号"。想重跑历史里的某条语句,用上下箭头翻出来,或 \e 编辑。

  4. \e 编辑长查询\e 会打开 $EDITOR(默认 vi)编辑当前缓冲,保存退出即执行。写复杂 SQL 时比在终端里逐行敲舒服得多

  5. 复制上一条语句改:输入 \e 后可以基于缓冲修改,不用重敲

附录:常用元命令速查表

-- —— 连接与数据库 ——
\l / \list            列出数据库
\c dbname [user]      切换数据库(可换用户)
\conninfo             当前连接信息
\du [pattern]         列出角色
\dn                   列出 schema

-- —— 看结构 ——
\d [table]            列出对象 / 看表结构
\d+ table             附大小和描述
\dt / \dv / \di / \ds / \df   表/视图/索引/序列/函数
\dp table             权限
\di+                  索引详情

-- —— 显示控制 ——
\x [auto]             扩展显示
\pset null '[NULL]'   空值显示
\pset border 2        边框
\timing [on|off]      显示耗时
\watch N              每 N 秒重跑
\o file / \o          输出到文件 / 恢复终端

-- —— 缓冲与编辑 ——
\p  打印缓冲    \e  编辑    \r  清空    \g  执行    \gx  扩展执行    \gset  存变量

-- —— 帮助 ——
\?                    元命令帮助
\h [SQL]              SQL 语法帮助

-- —— 其他 ——
\i file.sql           执行文件
\copy ...             客户端导入导出
\echo text            打印文本
\q                    退出
# —— 命令行 ——
psql -U app -d db                  交互连接
psql -c "SELECT 1"                 执行一条
psql -f file.sql -v ON_ERROR_STOP=1 执行文件(遇错即停)
psql -A -t -c "SQL"                无对齐输出,便于脚本
psql --csv -c "SQL" > out.csv      输出 CSV

# —— 备份恢复 ——
pg_dump -Fc db > db.dump           自定义格式(推荐)
pg_dump -Fd -j 4 db -f /backup/dir 并行导出
pg_restore -d db db.dump           恢复

学习资源

  1. psql 官方文档 —— 元命令的权威列表
  2. PostgreSQL 官方教程
  3. PostgreSQL 速查表(官方 wiki) —— 实战片段
  4. pgAdmin —— 图形化管理工具

psql 最值得记的就三组:看结构\d 家族,看宽表\x auto传数据\copy。另外把 ON_ERROR_STOP=1 写进脚本——默认忽略错误继续跑,是批量运维里最危险的行为。

参考&致谢

系列教程

全部文章RSS订阅

数据库系列


PostgreSQL命令行使用教程:掌握 psql 工具
发布于
2025年11月22日
许可协议。转载请注明来源
评论
数据加载中 ...
 上一篇

阅读全文

MySQL命令行使用全面教程:从入门到精通
MySQL命令行使用全面教程:从入门到精通 MySQL命令行使用全面教程:从入门到精通
mysql 命令行客户端是每个后端和运维都要打交道的工具。它有不少自己的选项和技巧——垂直输出、批处理模式、tee、备份参数——用好了能省很多事。本文从连接讲起,覆盖批处理、导入导出、性能诊断和常见故障处理。
2025-11-22
下一篇 

阅读全文

SQL命令使用教程:从入门到精通
SQL命令使用教程:从入门到精通 SQL命令使用教程:从入门到精通
SQL 是关系型数据库的通用语言,几乎所有数据库都支持。不过各家实现在细节上有差别,也就是所谓的"方言"。本文系统讲解 SQL 的核心命令,并用表格整理 MySQL、PostgreSQL、SQLite 之间的语法差异,方便对照查阅。
2025-11-22