psql 元命令(\d / \dt / \du)
psql 是 PostgreSQL 的官方命令行客户端。除了执行 SQL,它还提供了一组以反斜杠开头的「元命令(meta-command)」,用于探查数据库结构、查看权限、切换输出格式、执行脚本与变量替换。这些命令不需要分号结尾,也不发送给服务器——除了 \d 系列会转换为系统目录查询外,其余大多由 psql 本地解析。掌握元命令是日常运维与排障的基本功。
前置知识
阅读本节前,建议先了解:COALESCE / NULLIF / GREATEST / LEAST
基础概念
| 概念 | 术语 | 说明 |
|---|---|---|
| 元命令 | Meta-Command | 以 \ 开头的客户端命令,由 psql 本地解析 |
| 描述命令 | \d Family | 查看表、索引、序列、视图、函数等对象的定义 |
| 系统目录 | System Catalog | pg_class、pg_attribute 等存放元数据的系统表 |
| 扩展显示 | Expanded Display | \x 把结果按「列名 | 值」竖排,适合宽表 |
| 输出格式 | Output Format | \pset 控制对齐、边框、NULL 显示、分页等 |
| 变量 | psql Variable | \set 定义的客户端变量,用 :'var' 安全插值 |
| 脚本执行 | \i / \ir | 执行 SQL 文件;\ir 相对当前脚本路径解析 |
| 条件执行 | \if Family | \if / \elif / \else / \endif 控制脚本分支 |
| 启动配置 | .psqlrc | 每次启动自动执行的初始化脚本 |
| 监听刷新 | \watch | 周期性重复执行上一条查询并刷新输出 |
元命令与 SQL 的区别:
- 元命令不需要分号,一行一条(除非用
\续行)。 - 元命令不做 SQL 语法解析,参数按空白切分。
- 元命令大多不发给服务器,只有
\d系列、\copy、\watch等会与服务器交互。
# 在 psql 交互式会话中,元命令直接输入即可
\conninfo # 显示当前连接信息
\dt # 列出当前 schema 的表
\d products # 查看 products 表的定义语法与用法
常用元命令速查(按用途分组):
| 用途 | 命令 | 说明 |
|---|---|---|
| 帮助 | \? | 列出所有元命令 |
| 帮助 | \h SQL | 查看某条 SQL 的语法 |
| 列出对象 | \d | 列出所有可见对象 |
| 列出表 | \dt | 列出表(含 schema、类型、属主) |
| 列出索引 | \di | 列出索引 |
| 列出序列 | \ds | 列出序列 |
| 列出视图 | \dv | 列出视图 |
| 列出物化视图 | \dm | 列出物化视图 |
| 列出函数 | \df | 列出函数(含参数与返回类型) |
| 列出 schema | \dn | 列出 schema |
| 列出扩展 | \dx | 列出已安装扩展 |
| 列出角色 | \du | 列出角色与权限 |
| 列出权限 | \dp | 列出表/视图的访问权限 |
| 查看定义 | \d+ name | 查看对象详细定义(含注释、大小) |
| 含系统对象 | \dS | 加 S 后缀包含系统对象 |
| 显示原始 SQL | \sf func | 显示函数定义源码 |
| 切换格式 | \x | 切换扩展显示(竖排/横排) |
| 设置参数 | \pset | 调整输出格式 |
| 计时 | \timing | 开关 SQL 执行计时 |
| 执行文件 | \i file | 执行 SQL 文件 |
| 执行文件 | \ir file | 相对当前脚本目录执行 |
| 输出重定向 | \o file | 把后续结果写入文件 |
| 客户端导入导出 | \copy | 客户端侧 COPY,支持文件路径 |
| 重复执行 | \g / \gx | 重新执行查询缓冲 |
| 周期刷新 | \watch 5 | 每 5 秒重复执行上一条查询 |
| 编辑缓冲 | \e | 用编辑器打开当前查询缓冲 |
| 定义变量 | \set v val | 定义客户端变量 |
| 引用变量 | :'v' / :"v" | 安全插值(带引号 / 标识符) |
| 条件 | \if \elif \else \endif | 脚本条件分支 |
| 连接 | \c dbname | 切换数据库 |
| 连接信息 | \conninfo | 显示当前连接 |
| 退出 | \q | 退出 psql |
# 最常用的探查三连
\dt # 我有哪些表?
\d products # 这张表长什么样?
\du # 有哪些角色、权限如何?详细说明
\d 系列:对象探查
\d 是「describe」的缩写,是使用频率最高的一组命令。它支持通配符匹配。
# 列出所有对象(表、视图、序列、索引都在内)
\d
# 只看表;*.* 表示所有 schema
\dt
\dt *.*
# 通配符匹配表名
\dt public.order*
# 查看单个表的完整定义(列、类型、约束、索引、触发器、属主)
\d products\d products 的典型输出:
Table "public.products"
Column | Type | Collation | Nullable | Default
----------+------------------------+-----------+----------+--------------------------------------
id | integer | | not null | generated always as identity
sku | text | | not null |
name | text | | not null |
price | numeric(10,2) | | |
stock | integer | | not null | 0
Indexes:
"products_pkey" PRIMARY KEY, btree (id)
"products_sku_key" UNIQUE CONSTRAINT, btree (sku)加 + 后缀会输出更多信息:注释、存储参数、表大小、访问方式等。
\d+ products Table "public.products"
Column | Type | ... | Storage | Stats target | Description
----------+------------------------+-----+----------+--------------+-------------
id | integer | ... | plain | |
price | numeric(10,2) | ... | main | |
...
Has OIDs: no
Options: autovacuum_enabled=true\dt / \di / \ds / \dv:按类型列举
\d + 类型字母是固定组合,记住后缀字母即可:
| 后缀 | 含义 | 英文 |
|---|---|---|
t | 表 | table |
i | 索引 | index |
s | 序列 | sequence |
v | 视图 | view |
m | 物化视图 | materialized view |
f | 函数 | function |
n | schema | namespace |
x | 扩展 | extension |
p | 权限 | privileges |
u | 角色 | user |
# 只看索引
\di
# 只看当前库的扩展
\dx
# 列出所有 schema
\dn
# 列出角色
\du\du 与权限查看
\du 输出角色列表及其属性。
List of roles
Role name | Attributes
------------+------------------------------------------------------------
app_user |
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS
readonly | Cannot login要查看某张表的具体授权情况,用 \dp 或 \z:
\dp products
\z products Access privileges
Schema | Name | Type | Access privileges | Column privileges
--------+----------+----------+---------------------------+-------------------
public | products | table | postgres=arwdDxt/postgres+|
| | | app_user=arwd/postgres |权限字母含义:a = INSERT、r = SELECT、w = UPDATE、d = DELETE、D = TRUNCATE、x = REFERENCES、t = TRIGGER。
\x:扩展显示
宽表在终端里会被截断或换行错乱,\x 切换为竖排显示,一行一个字段,非常适合列多的表。
\x # 开启
SELECT * FROM products WHERE sku = 'SKU-1001';
\x # 关闭-[ RECORD 1 ]-----------
id | 1
sku | SKU-1001
name | 27 英寸显示器
price | 1299.00
stock | 12也可以用 \pset expanded on 达到同样效果,\x auto 则在输出过宽时自动切换。
\pset 与输出控制
\pset 控制结果集的呈现方式,常用的有:
| 参数 | 作用 | 常用值 |
|---|---|---|
format | 输出格式 | aligned、unaligned、csv、json、html |
expanded | 竖排显示 | on / off / auto |
null | NULL 的显示文本 | 如 NULL、(空) |
border | 边框样式 | 0、1、2 |
pager | 分页器 | on / off |
tuples_only | 只输出数据行 | on / off |
fieldsep | 分隔符 | ,、| |
# 导出为 CSV 风格
\pset format csv
\pset null '(空)'
SELECT sku, name, price FROM products LIMIT 3;
# 只输出数据、无表头与边框(便于脚本解析)
\pset tuples_only on
\pset format unaligned
SELECT sku FROM products;变量与安全插值
\set 定义客户端变量,用 :'var' 插入为字符串字面量(自动加引号并转义),:"var" 插入为标识符。
# 定义变量
\set tbl products
\set sku 'SKU-1001'
# 作为标识符(不加引号)
SELECT * FROM :"tbl" WHERE sku = :'sku';
# 查看已定义变量
\set
# 取消变量
\unset tbl关键安全点:用 :'var' 而不是字符串拼接,可以避免 SQL 注入。因为 psql 会正确转义单引号。
# 危险!若 :val 含单引号会语法错误或被注入
SELECT * FROM products WHERE name = ':val'; -- 错误!这是字面量文本
# 正确
SELECT * FROM products WHERE name = :'val';\i / \ir / \o / \copy:脚本与文件
# 执行 SQL 文件(相对当前工作目录)
\i /path/to/schema.sql
# 执行 SQL 文件(相对当前脚本所在目录)——脚本内嵌套调用时更安全
\ir ./seed.sql
# 把后续查询结果写入文件
\o /tmp/result.txt
SELECT * FROM products;
\o # 结束重定向,恢复标准输出
# 客户端侧 COPY:可读写客户端本地文件
\copy products TO '/tmp/products.csv' WITH (FORMAT csv, HEADER true)
\copy products FROM '/tmp/products.csv' WITH (FORMAT csv, HEADER true)\copy 与服务器端 COPY 的区别:\copy 由 psql 客户端读写文件,因此不需要超级用户权限,也不需要文件位于服务器上。
\g / \gx / \watch:重复与刷新
# \g 重新执行查询缓冲
SELECT * FROM products;
# \gx 以竖排方式执行
\gx
# \watch 周期执行上一条查询(默认 2 秒)
SELECT count(*) FROM orders;
\watch 5 # 每 5 秒刷新一次;Ctrl+C 退出\watch 常用于观察 pg_stat_activity、锁等待、复制延迟等动态指标。
\e / \ef / \sf:编辑与查看定义
# 用默认编辑器打开查询缓冲
\e
# 编辑函数定义并自动重建
\ef my_function
# 显示函数的定义源码
\sf my_function\if / \elif / \else / \endif:脚本条件
psql 支持在脚本中做条件判断,配合 \set 变量可实现简单的流程控制。
\set env 'prod'
\if :'env' = 'prod'
\echo '生产环境:只读操作'
\set readonly true
\elif :'env' = 'test'
\echo '测试环境:可写'
\set readonly false
\else
\echo '未知环境'
\endif.psqlrc:启动配置
~/.psqlrc 在每次启动交互式会话时自动执行,适合放置常用设置。
-- ~/.psqlrc
\set HISTSIZE 10000
\pset null '(NULL)'
\pset border 2
\timing on
\set PROMPT1 '%n@%/%R%# '
\set COMP_KEYWORD_CASE upper用 psql -X 可以跳过 .psqlrc 加载,做问题排查时非常有用。
反斜杠续行与批量命令
元命令可以用 \ 结尾续行,参数也可以多行书写。
# 内容含空格或反斜杠时用单引号包裹
\echo 'Hello, World'
# 查看某条 SQL 的命令语法
\h CREATE INDEX实战示例
步骤 1:建库建表并造数据
CREATE DATABASE demo;
\c demo
CREATE TABLE products (
id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
sku text NOT NULL UNIQUE,
name text NOT NULL,
price numeric(10, 2),
stock integer NOT NULL DEFAULT 0
);
CREATE INDEX idx_products_price ON products (price);
CREATE TABLE orders (
id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
order_no text NOT NULL,
product_id integer REFERENCES products (id),
qty integer NOT NULL
);
INSERT INTO products (sku, name, price, stock) VALUES
('SKU-1001', '27 英寸显示器', 1299.00, 12),
('SKU-1002', '机械键盘', 399.00, 30),
('SKU-1003', '无线鼠标', 159.00, 0);步骤 2:探查表结构
\d products Table "public.products"
Column | Type | Collation | Nullable | Default
----------+---------------+-----------+----------+--------------------------------------
id | integer | | not null | generated always as identity
sku | text | | not null |
name | text | | not null |
price | numeric(10,2) | | |
stock | integer | | not null | 0
Indexes:
"products_pkey" PRIMARY KEY, btree (id)
"products_sku_key" UNIQUE CONSTRAINT, btree (sku)
"idx_products_price" btree (price)
Referenced by:
TABLE "orders" CONSTRAINT "orders_product_id_fkey" FOREIGN KEY (product_id) REFERENCES products(id)步骤 3:列举对象与角色
\dt
\di
\du List of relations
Schema | Name | Type | Owner
--------+----------+-------+----------
public | orders | table | postgres
public | products | table | postgres
(2 rows)
List of indexes
Schema | Name | Type | Owner | Table
--------+---------------------+-------+----------+----------
public | idx_products_price | index | postgres | products
public | orders_pkey | index | postgres | orders
public | products_pkey | index | postgres | products
public | products_sku_key | index | postgres | products
(4 rows)
List of roles
Role name | Attributes
-----------+------------------------------------------------------------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS
(1 row)步骤 4:竖排显示与格式控制
\x
SELECT * FROM products WHERE sku = 'SKU-1001';-[ RECORD 1 ]-----------
id | 1
sku | SKU-1001
name | 27 英寸显示器
price | 1299.00
stock | 12\pset format csv
\pset null '(空)'
SELECT sku, name, price FROM products ORDER BY sku;sku,name,price
SKU-1001,27 英寸显示器,1299.00
SKU-1002,机械键盘,399.00
SKU-1003,无线鼠标,159.00步骤 5:变量插值
\set tbl products
\set min_price 200
SELECT sku, name, price
FROM :"tbl"
WHERE price > :min_price
ORDER BY price; sku | name | price
----------+------------+---------
SKU-1002 | 机械键盘 | 399.00
SKU-1001 | 27 英寸显示器 | 1299.00
(2 rows)步骤 6:脚本执行与结果导出
# 把查询结果导出为 CSV
\pset format csv
\o /tmp/products_report.csv
SELECT sku, name, coalesce(price, 0) AS price FROM products ORDER BY sku;
\o
# 查看文件(在 shell 中)
\! head -n 3 /tmp/products_report.csvsku,name,price
SKU-1001,27 英寸显示器,1299.00
SKU-1002,机械键盘,399.00注意事项
- 元命令不加分号。 加了分号会被当作 SQL 文本的一部分,导致语法错误或行为不符预期。
\dt; -- 错误!分号会被当作参数元命令不支持事务内的服务器端回滚。 元命令是客户端行为,
BEGIN中的\d不会回滚,且\copy走单独的连接上下文。\d系列查的是系统目录,权限不足时对象不可见。 看不到某张表可能只是没有权限,而非表不存在。\i与\ir的路径解析不同。\i相对当前工作目录,\ir相对当前正在执行的脚本目录;嵌套脚本一律用\ir。
\i ./sub/init.sql -- 相对进程工作目录,易出错
\ir ./sub/init.sql -- 相对本脚本目录,推荐- 变量插值必须用
:'var'。 直接写:var或字符串拼接会带来语法错误与注入风险。
-- 错误!这是普通字符串,不会替换变量
WHERE name = ':val'
-- 正确
WHERE name = :'val'\pset format等设置在会话内持续生效。 若在脚本中修改,记得用完恢复,否则影响后续输出。\x是开关,不是固定开启。 连续按两次会回到横排,脚本中建议显式写\x on/\x off。\watch会持续占用连接。 忘记Ctrl+C可能导致连接被长期占用,生产环境注意使用频率与超时。不要在生产库直接执行
\copy ... FROM。 客户端路径导入同样会写入数据,误用可能污染生产数据。
最佳实践
- 把常用设置写进
~/.psqlrc,统一 NULL 显示、边框与计时,减少重复输入。
-- ~/.psqlrc
\pset null '(NULL)'
\pset border 2
\timing on- 排查问题的第一步固定为「三连」:
\conninfo、\dt、\d 表名,快速建立环境与结构认知。
\conninfo
\dt
\d products- 宽表查询一律先
\x,避免终端换行错乱导致误读数据。
\x on
SELECT * FROM pg_stat_activity WHERE state <> 'idle';脚本中一律用
\ir,保证无论从哪个目录调用都能正确定位相对文件。变量插值统一用
:'var'/:"var",绝不拼接字符串,从源头规避注入。
\set schema public
SELECT count(*) FROM :"schema".products;- 用
\dp定期复核权限,尤其是生产库中对publicschema 的默认授权。
\dp
\dn+- 导出数据优先用
\copy而非服务器端COPY,免去超级用户与服务器文件路径的约束。
\copy (SELECT sku, name FROM products) TO '/tmp/out.csv' WITH (FORMAT csv, HEADER true)- 在 CI 或迁移脚本中用
psql -v ON_ERROR_STOP=1,让任意 SQL 失败立即中止,避免半成品状态。
psql -v ON_ERROR_STOP=1 -d demo -f migrate.sql- 用
\timing+\watch组合做轻量性能观察,快速定位慢查询与锁等待,无需额外工具。
\timing on
SELECT count(*) FROM orders;
\watch 2下一节
继续学习:EXPLAIN 执行计划