PostgreSQLpsql数据库交互终端技能Skill postgresql-psql

PostgreSQL psql 是 PostgreSQL 数据库的交互式终端客户端,用于连接数据库、执行 SQL 查询、管理数据库对象(如表、视图、索引)、备份和恢复数据、配置连接选项、格式化输出、编写自动化脚本、管理事务等。适用于数据库管理、后端开发、DevOps 运维和 SQL 调试。关键词:PostgreSQL, psql, 数据库管理, SQL 查询, 交互终端, 备份恢复, 事务处理, 脚本自动化, DevOps, 数据库运维。

后端开发 0 次安装 0 次浏览 更新于 3/18/2026

name: postgresql-psql description: PostgreSQL psql 的全面指南 - PostgreSQL 的交互式终端客户端。用于连接 PostgreSQL 数据库、执行查询、管理数据库/表、配置连接选项、格式化输出、编写脚本、管理事务,以及使用高级 psql 功能进行数据库管理和开发。 license: PostgreSQL version: 1.0.0

PostgreSQL psql 技能

PostgreSQL psql(PostgreSQL 交互式终端)是用于与 PostgreSQL 数据库交互的主要命令行客户端。它提供交互式查询执行和强大的脚本功能,用于数据库管理和运维。

何时使用此技能

使用此技能当:

  • 从命令行连接 PostgreSQL 数据库
  • 交互式执行 SQL 查询
  • 编写 SQL 脚本进行自动化
  • 创建和管理数据库与模式
  • 管理数据库对象(表、视图、索引、函数)
  • 备份和恢复数据库
  • 配置连接和认证
  • 格式化和导出查询结果
  • 管理事务和权限
  • 调试 SQL 查询
  • 自动化数据库管理任务
  • 设置复制和高可用性
  • 创建存储过程和函数

核心概念

REPL 模型

  • psql 作为交互式 REPL(读取-求值-打印循环)运行
  • 接受 SQL 命令和元命令(反斜杠命令)
  • 在会话中跨命令维护连接状态
  • 支持命令历史和编辑

命令类型

  • SQL 命令:标准 SQL 语句(SELECT、INSERT、UPDATE、DELETE 等)
  • 元命令:psql 特定命令,前缀为反斜杠(如 \dt\d
  • 反斜杠命令:控制查询输出、会话变量和 psql 行为

连接模型

  • 每个会话单一数据库连接
  • 可以在不重新连接的情况下切换数据库
  • 连接状态包括当前数据库、用户和搜索路径
  • 环境变量和 .pgpass 用于凭据管理

连接选项

基本连接命令

psql [OPTIONS] [DBNAME [USERNAME]]

常见连接选项

# 使用用户名和主机连接
psql -U username -h hostname -p 5432 -d database_name

# 使用连接字符串连接
psql postgresql://username:password@hostname:5432/database_name

# 使用密码提示连接
psql -U postgres -h localhost -W

# 连接到本地机器的特定数据库
psql -d myapp_development

# 环境变量(替代方法)
export PGUSER=postgres
export PGPASSWORD=mypassword
export PGHOST=localhost
export PGPORT=5432
export PGDATABASE=mydb
psql

连接字符串格式

标准 URI 格式

postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]

示例

postgresql://app_user:secretpass@db.example.com:5432/production_db?sslmode=require

认证方法

密码文件(.pgpass)

# ~/.pgpass(chmod 600)
hostname:port:database:username:password
localhost:5432:mydb:postgres:mypassword
*.example.com:5432:*:appuser:apppass

通过 SSH 隧道连接

ssh -L 5432:localhost:5432 user@remote-host
psql -U postgres -h localhost

SSL/TLS 连接选项

# 要求 SSL
psql -h hostname -sslmode require -U username database

# 验证证书
psql -h hostname -sslmode verify-full \
  -sslcert=/path/to/client-cert.crt \
  -sslkey=/path/to/client-key.key \
  -sslrootcert=/path/to/ca-cert.crt database

# SSL 模式:disable、allow、prefer(默认)、require、verify-ca、verify-full

基本元命令

数据库和模式导航

\l 或 \list                    # 列出所有数据库
\l+ 或 \list+                  # 列出数据库及其大小
\c 或 \connect DATABASE USER   # 连接到不同数据库
\dn 或 \dn+                    # 列出模式(命名空间)
\dt 或 \dt+                    # 列出当前模式中的表
\di 或 \di+                    # 列出索引
\dv 或 \dv+                    # 列出视图
\dm 或 \dm+                    # 列出物化视图
\ds 或 \ds+                    # 列出序列
\df 或 \df+                    # 列出函数/过程
\da 或 \da+                    # 列出聚合函数
\dT 或 \dT+                    # 列出数据类型
\dF 或 \dF+                    # 列出文本搜索配置

对象检查命令

\d 或 \d NAME                  # 描述表、视图、索引、序列或函数
\d+ 或 \d+ NAME                # 扩展描述,带详细信息
\da PATTERN                    # 列出匹配模式的聚合函数
\db 或 \db+                    # 列出表空间
\dc 或 \dc+                    # 列出字符集编码
\dC 或 \dC+                    # 列出类型转换
\dd 或 \dd+                    # 列出对象描述/注释
\dD 或 \dD+                    # 列出域
\de 或 \de+                    # 列出外部数据包装器
\dE 或 \dE+                    # 列出外部服务器
\dF 或 \dF+                    # 列出文本搜索配置
\dFd 或 \dFd+                  # 列出文本搜索字典
\dFp 或 \dFp+                  # 列出文本搜索解析器
\dFt 或 \dFt+                  # 列出文本搜索模板
\dg 或 \dg+                    # 列出数据库角色/用户
\dl 或 \dl+                    # 列出大对象(同 \lo_list)
\dL 或 \dL+                    # 列出过程语言
\dO 或 \dO+                    # 列出排序规则
\dp 或 \dp+                    # 列出表访问权限
\dRp 或 \dRp+                  # 列出复制源
\dRs 或 \dRs+                  # 列出复制订阅
\ds 或 \ds+                    # 列出序列
\dt 或 \dt+                    # 列出表
\dU 或 \dU+                    # 列出用户映射
\du 或 \du+                    # 列出角色
\dv 或 \dv+                    # 列出视图
\dx 或 \dx+                    # 列出扩展
\dX 或 \dX+                    # 列出扩展统计

格式化和输出命令

\a                             # 切换对齐和非对齐输出
\C [STRING]                    # 设置表标题
\f [STRING]                    # 为非对齐输出设置字段分隔符
\H                             # 切换 HTML 输出模式
\pset OPTION [VALUE]           # 设置输出选项(详见下文)
\t [on|off]                    # 切换仅元组输出(无头尾)
\T [STRING]                    # 设置 HTML 表标签属性
\x 或 \x [on|off|auto]         # 切换扩展/垂直输出
\g 或 \g [FILENAME|COMMAND]    # 执行查询并将输出发送到文件/命令

\pset 选项

\pset border [0-2]             # 设置边框显示(0=无,1=ascii,2=unicode)
\pset columns WIDTH            # 设置列宽限制
\pset csv                      # 设置 CSV 输出格式
\pset expanded [on|off|auto]   # 切换扩展输出
\pset fieldsep STRING          # 设置字段分隔符
\pset footer [on|off]          # 切换页脚显示
\pset format [aligned|unaligned|csv|tsv|html|latex|latex-longtable|troff-ms]
\pset header [on|off]          # 切换页眉显示
\pset linestyle [ascii|old-ascii|unicode] # 设置线绘制样式
\pset null STRING              # 设置表示 NULL 的字符串
\pset numericlocale [on|off]   # 切换区域特定的数字格式
\pset pager [on|off|always]    # 控制分页器使用
\pset recordsep STRING         # 设置记录分隔符
\pset recordsep0 [on|off]      # 使用空终止符分隔记录
\pset tableattr STRING         # 设置 HTML 表属性
\pset title STRING             # 设置查询标题
\pset tuples_only [on|off]     # 切换仅元组模式

文件和历史命令

\copy QUERY TO FILENAME [FORMAT]          # 客户端 COPY(需要较少权限)
\copy QUERY TO STDOUT                     # 复制到标准输出
\copy TABLE FROM FILENAME [FORMAT]        # 从文件导入数据
\e 或 \edit                               # 在编辑器中编辑当前查询缓冲区
\e FILENAME                               # 在编辑器中编辑文件
\ef [FUNCNAME]                            # 编辑函数定义
\ev [VIEWNAME]                            # 编辑视图定义
\w FILENAME 或 \write FILENAME            # 将当前查询缓冲区写入文件
\i FILENAME 或 \include FILENAME          # 从文件执行 SQL 命令
\ir FILENAME 或 \include_relative FILE    # 执行相对路径文件
\s [FILENAME]                             # 显示命令历史(或保存到文件)
\o FILENAME 或 \out FILENAME              # 将所有输出发送到文件
\o                                        # 将输出返回到终端

批处理和脚本命令

\echo TEXT                     # 打印文本(在脚本中有用)
\errverbose                    # 以详细形式显示最后错误
\q 或 \quit                    # 退出 psql
\! COMMAND 或 \shell COMMAND   # 执行 shell 命令
\cd DIRECTORY                  # 更改工作目录
\pwd                           # 打印当前工作目录
\set VARIABLE VALUE            # 设置 psql 变量
\unset VARIABLE                # 取消设置 psql 变量
\setenv VARNAME VALUE          # 设置环境变量
\getenv VARNAME                # 获取环境变量值
\prompt [TEXT] VARIABLE        # 提示用户输入并设置变量

事务命令

\begin 或 BEGIN                # 开始事务
\commit 或 COMMIT              # 提交事务
\rollback 或 ROLLBACK          # 回滚事务
\savepoint NAME                # 创建保存点
\release SAVEPOINT             # 释放保存点
\rollback TO SAVEPOINT         # 回滚到保存点

信息命令

\d+ TABLENAME                  # 显示表及其扩展信息和存储信息
\dt *.*                        # 列出所有模式中的所有表
\dn *                          # 列出所有模式
\du                            # 列出所有用户/角色
\db                            # 列出表空间
\dx                            # 列出已安装的扩展
\h 或 \help                    # 列出可用的 SQL 命令
\h COMMAND 或 \help COMMAND    # 显示特定 SQL 命令的帮助
\?                             # 显示 psql 帮助
\copyright                     # 显示 PostgreSQL 版权/许可信息
\version 或 SELECT version()   # 显示 PostgreSQL 版本

命令行选项

连接选项

-h, --host=HOSTNAME           # 服务器主机名(默认:localhost)
-p, --port=PORT               # 服务器端口(默认:5432)
-U, --username=USERNAME       # PostgreSQL 用户名(默认:$USER)
-d, --dbname=DBNAME           # 要连接的数据库名
-w, --no-password             # 从不提示密码
-W, --password                # 强制密码提示

输出和格式化选项

-A, --no-align                # 非对齐表输出模式
-c, --command=COMMAND         # 运行单个命令并退出
-C, --copy-only               # (已弃用,使用 \copy 代替)
-d, --dbname=DBNAME           # 指定数据库
-E, --echo-hidden             # 显示内部查询
-e, --echo-all                # 发送前显示每个命令
-b, --echo-errors             # 显示失败命令
-f, --file=FILENAME           # 从文件执行命令
-F, --field-separator=CHAR    # 为非对齐输出设置字段分隔符
-H, --html                    # HTML 表输出模式
-l, --list                    # 列出可用数据库并退出
-L, --log-file=FILENAME       # 将会话记录到文件
-n, --no-readline             # 禁用 readline(行编辑)
-o, --output=FILENAME         # 将结果写入文件
-P, --pset=VARIABLE=VALUE     # 设置打印选项
-q, --quiet                   # 静默运行(无横幅,单行模式)
-R, --record-separator=CHAR   # 为非对齐输出设置记录分隔符
-S, --single-step             # 单步模式(确认每个命令)
-s, --single-transaction      # 在单个事务中执行文件
-t, --tuples-only             # 仅打印行(无头尾)
-T, --table-attr=STRING       # 设置 HTML 表标签属性
-v, --set=VARIABLE=VALUE      # 设置 psql 变量
-V, --version                 # 显示版本并退出
-x, --expanded                # 扩展表输出模式
-X, --no-psqlrc               # 不读取 ~/.psqlrc 启动文件
-1, --single-line             # 行尾终止 SQL 命令

其他选项

-a, --all                     # (已弃用)
-j, --job=NUM                 # (用于 pg_dump 的并行转储)
--help                        # 显示帮助消息
--version                     # 显示版本
--on-error-stop               # 在首次错误时停止

变量和配置

内置变量

# 提示变量
psql -v PROMPT1='%/%R%# '     # 设置主提示
psql -v PROMPT2='%R%# '       # 设置续行提示
psql -v PROMPT3='>> '         # 设置输出模式提示

# 提示扩展代码:
# %n = 数据库用户名
# %m = 数据库服务器主机名(第一部分)
# %> = 数据库服务器主机名完整
# %p = 数据库服务器端口
# %d = 数据库名
# %/ = 当前模式
# %~ = 类似 %/,但如果模式匹配用户名则为 ~
# %# = 如果是超级用户则为 #,否则为 >
# %? = 最后查询结果状态
# %% = 文字 %
# %[..%] = 不可见字符(用于终端控制序列)

配置文件(~/.psqlrc)

# psql 启动时自动加载
# 设置默认选项
\set QUIET ON
\set SQLHISTSIZE 10000

# 配置输出
\pset null '[NULL]'
\pset border 2
\pset linestyle unicode
\pset expanded auto
\pset pager always

# 定义有用变量
\set conn_user 'SELECT current_user;'
\set dbsize 'SELECT pg_size_pretty(pg_database_size(current_database()));'
\set tables 'SELECT tablename FROM pg_tables WHERE schemaname = ''public'';'
\set functions 'SELECT proname FROM pg_proc;'

# 定义快捷方式
\set uptime 'SELECT now() - pg_postmaster_start_time() AS uptime;'
\set locks 'SELECT pid, usename, pg_blocking_pids(pid) as blocked_by, query, state FROM pg_stat_activity WHERE cardinality(pg_blocking_pids(pid)) > 0;'

# 设置计时
\timing ON

# 连接到默认数据库
\c mydb

变量替换

-- 使用 :variable 语法
\set table_name mytable
SELECT * FROM :table_name;

-- 使用 :'variable' 用于文字字符串
\set schema_name public
SELECT * FROM :"schema_name".mytable;

-- 使用 :'variable' 语法在字符串上下文中
\set username 'postgres'
SELECT * FROM pg_tables WHERE tableowner = :'username';

-- 使用 :' ' 用于标识符引用
\set id_name "customTable"
SELECT * FROM :"id_name";

基本 SQL 操作

查询执行

-- 简单查询,立即执行
SELECT * FROM users;

-- 多行查询(直到分号)
SELECT id, name, email
FROM users
WHERE active = true;

-- 查询结果到文件
SELECT * FROM large_table \g output.txt

-- 查询管道到命令
SELECT * FROM users \g | wc -l

-- 执行先前命令
\g

-- 作为仅元组执行(无头尾)
SELECT * FROM users;

创建对象

-- 创建数据库
CREATE DATABASE myapp_db;

-- 创建模式
CREATE SCHEMA app_schema;

-- 创建表
CREATE TABLE app_schema.users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 创建索引
CREATE INDEX idx_users_email ON app_schema.users(email);

-- 创建视图
CREATE VIEW app_schema.active_users AS
SELECT id, name, email FROM app_schema.users WHERE active = true;

-- 创建函数
CREATE OR REPLACE FUNCTION app_schema.get_user_count()
RETURNS INTEGER AS $$
BEGIN
  RETURN (SELECT COUNT(*) FROM app_schema.users);
END;
$$ LANGUAGE plpgsql;

数据操作

-- 插入单行
INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com');

-- 插入多行
INSERT INTO users (name, email) VALUES
  ('Jane Smith', 'jane@example.com'),
  ('Bob Johnson', 'bob@example.com');

-- 从查询插入
INSERT INTO users_backup SELECT * FROM users;

-- 更新数据
UPDATE users SET active = false WHERE last_login < now() - interval '30 days';

-- 删除数据
DELETE FROM users WHERE id = 999;

-- RETURNING 子句(查看更改内容)
UPDATE users SET status = 'active' 
WHERE id = 1 
RETURNING id, name, status;

事务管理

事务控制

-- 开始事务
BEGIN;
-- 或
START TRANSACTION;

-- 提交更改
COMMIT;
-- 或
END;

-- 回滚更改
ROLLBACK;

-- 创建保存点
SAVEPOINT sp1;
-- ... 执行语句 ...
ROLLBACK TO sp1;  # 回滚到保存点
RELEASE sp1;      # 释放保存点

-- 多语句事务
BEGIN;
  INSERT INTO accounts (name, balance) VALUES ('Alice', 1000);
  INSERT INTO accounts (name, balance) VALUES ('Bob', 1000);
  UPDATE accounts SET balance = balance - 100 WHERE name = 'Alice';
  UPDATE accounts SET balance = balance + 100 WHERE name = 'Bob';
COMMIT;

事务隔离级别

-- 设置事务隔离级别
BEGIN TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;  # PostgreSQL 默认
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- 显示当前事务状态
SHOW transaction_isolation;

高级功能

全文搜索

-- 创建全文搜索向量
ALTER TABLE documents ADD COLUMN search_vector tsvector;

UPDATE documents SET search_vector = 
  to_tsvector('english', coalesce(title, '') || ' ' || coalesce(content, ''));

-- 创建索引以便快速搜索
CREATE INDEX idx_documents_search ON documents USING GIN(search_vector);

-- 搜索文档
SELECT * FROM documents 
WHERE search_vector @@ to_tsquery('english', 'database & tutorial');

-- 按相关性排序结果
SELECT id, title, ts_rank(search_vector, query) AS rank
FROM documents, to_tsquery('english', 'database') AS query
WHERE search_vector @@ query
ORDER BY rank DESC;

窗口函数

-- 行号
SELECT id, name, salary,
  ROW_NUMBER() OVER (ORDER BY salary DESC) AS rank
FROM employees;

-- 运行总和
SELECT id, amount, date,
  SUM(amount) OVER (ORDER BY date) AS running_total
FROM transactions;

-- 分区结果
SELECT id, department, salary,
  ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank
FROM employees;

-- LEAD/LAG(下一行/上一行)
SELECT id, date, amount,
  LAG(amount) OVER (ORDER BY date) AS prev_amount,
  LEAD(amount) OVER (ORDER BY date) AS next_amount
FROM transactions;

JSON 操作

-- 存储 JSON
INSERT INTO documents VALUES (1, '{"name": "Alice", "age": 30}');

-- 访问 JSON 字段
SELECT data -> 'name' AS name FROM documents;

-- 访问并返回文本
SELECT data ->> 'name' AS name_text FROM documents;  # 返回文本

-- 检查键是否存在
SELECT * FROM documents WHERE data ? 'name';

-- JSON 数组操作
SELECT json_array_length(data) FROM documents;

-- JSON 聚合
SELECT json_agg(name) FROM users;

-- JSONB(二进制 JSON)性能更佳
CREATE TABLE config (id INT, settings JSONB);
INSERT INTO config VALUES (1, '{"theme": "dark", "lang": "en"}');

-- JSONB 操作符更高效
SELECT settings @> '{"theme": "dark"}' FROM config;

公用表表达式(CTE)

-- 简单 CTE
WITH active_users AS (
  SELECT id, name, email FROM users WHERE active = true
)
SELECT * FROM active_users WHERE created_at > '2024-01-01';

-- 递归 CTE(树遍历)
WITH RECURSIVE category_hierarchy AS (
  SELECT id, name, parent_id, 0 AS level
  FROM categories
  WHERE parent_id IS NULL
  
  UNION ALL
  
  SELECT c.id, c.name, c.parent_id, h.level + 1
  FROM categories c
  JOIN category_hierarchy h ON c.parent_id = h.id
)
SELECT * FROM category_hierarchy;

-- 多个 CTE
WITH orders_2024 AS (
  SELECT * FROM orders WHERE EXTRACT(YEAR FROM order_date) = 2024
),
customer_totals AS (
  SELECT customer_id, SUM(total_amount) AS total
  FROM orders_2024
  GROUP BY customer_id
)
SELECT c.name, ct.total
FROM customers c
JOIN customer_totals ct ON c.id = ct.customer_id
ORDER BY ct.total DESC;

使用 psql 脚本

运行 SQL 文件

# 执行文件
psql -d mydb -f script.sql

# 执行并输出到文件
psql -d mydb -f script.sql -o results.txt

# 执行并在错误时停止
psql -d mydb -f script.sql --on-error-stop

# 在单个事务中执行
psql -d mydb -f script.sql -s

# 多个文件(按顺序执行)
psql -d mydb -f init.sql -f seed.sql -f verify.sql

SQL 脚本最佳实践

-- sample_script.sql

-- 设置执行模式
\set ON_ERROR_STOP ON
\set QUIET OFF

-- 如果需要,删除现有对象
DROP TABLE IF EXISTS temp_table;

-- 创建表
CREATE TABLE temp_table (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL
);

-- 插入数据
INSERT INTO temp_table (name) VALUES
  ('Record 1'),
  ('Record 2'),
  ('Record 3');

-- 验证结果
SELECT * FROM temp_table;

-- 清理
DROP TABLE temp_table;

-- 报告
\echo 'Script completed successfully!'

动态 SQL 脚本

#!/bin/bash

# 使用 psql 变量的 Bash 脚本
DATABASE="myapp_db"
TABLE_NAME="users"
SCHEMA_NAME="public"

# 执行变量替换
psql -d $DATABASE -v table_name=$TABLE_NAME \
  -v schema_name=$SCHEMA_NAME -c "
  SELECT COUNT(*) FROM :schema_name.:table_name;
"

# 循环遍历数据库
for db in $(psql -l | awk '{print $1}'); do
  if [[ ! "$db" =~ "template" ]]; then
    echo "Backing up $db..."
    pg_dump $db > /backups/$db.sql
  fi
done

导入和导出

COPY 命令

-- 服务器端 COPY(需要对文件操作具有超级用户权限)
COPY users (id, name, email) 
TO '/tmp/users.csv' 
WITH (FORMAT CSV, HEADER TRUE, QUOTE '"', ESCAPE '\\');

-- 导入 CSV
COPY users (id, name, email)
FROM '/tmp/users.csv'
WITH (FORMAT CSV, HEADER TRUE, QUOTE '"', ESCAPE '\\');

-- 制表符分隔值
COPY users TO '/tmp/users.tsv' WITH (FORMAT TEXT, DELIMITER E'\t');

-- 处理 NULL
COPY users TO '/tmp/users.csv' 
WITH (FORMAT CSV, NULL 'N/A', QUOTE '"');

客户端 COPY(\copy)

# 导出到 CSV(从 psql)
\copy users TO '/home/user/users.csv' WITH (FORMAT CSV, HEADER)

# 导出查询结果
\copy (SELECT id, name, email FROM users WHERE active = true) \
  TO '/tmp/active_users.csv' WITH (FORMAT CSV, HEADER)

# 导入 CSV
\copy users (id, name, email) FROM '/tmp/users.csv' WITH (FORMAT CSV, HEADER)

# 导出到标准输出(管道到文件)
\copy users TO STDOUT WITH (FORMAT CSV, HEADER) > users.csv

# 从标准输入导入
cat users.csv | \copy users FROM STDIN WITH (FORMAT CSV, HEADER)

使用 pg_dump 和 pg_restore

# 转储整个数据库
pg_dump -d mydb -U postgres > mydb_backup.sql

# 自定义格式转储(压缩)
pg_dump -d mydb -Fc > mydb_backup.dump

# 转储特定表
pg_dump -d mydb -t users > users_backup.sql

# 仅转储数据
pg_dump -d mydb -a > mydb_data.sql

# 仅转储模式
pg_dump -d mydb -s > mydb_schema.sql

# 从 SQL 文件恢复
psql -d mydb_restored -f mydb_backup.sql

# 从自定义格式恢复
pg_restore -d mydb_restored mydb_backup.dump

# 列出转储内容
pg_restore -l mydb_backup.dump

性能和调试

查询分析

-- 显示查询执行计划
EXPLAIN SELECT * FROM users WHERE id = 1;

-- 详细分析实际执行
EXPLAIN ANALYZE SELECT * FROM users WHERE id = 1;

-- 显示更多细节
EXPLAIN (ANALYZE, BUFFERS, VERBOSE) 
  SELECT * FROM users WHERE active = true;

-- JSON 输出用于程序解析
EXPLAIN (FORMAT JSON, ANALYZE)
  SELECT COUNT(*) FROM users;

查看查询性能

-- 当前查询
SELECT pid, usename, state, query FROM pg_stat_activity;

-- 长时间运行查询
SELECT pid, usename, now() - query_start AS duration, query
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY query_start;

-- 阻塞查询
SELECT blocked_pid, blocking_pid, blocked_statement, blocking_statement
FROM pg_stat_statements;

-- 表大小
SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
FROM pg_tables
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;

-- 数据库大小
SELECT pg_size_pretty(pg_database_size('mydb'));

设置计时

# 启用查询计时
\timing ON

# 禁用查询计时
\timing OFF

# 在批处理模式中
psql -d mydb -c "\timing ON" -f script.sql

查询日志记录

# 记录所有查询到文件
psql -d mydb -L query.log -f script.sql

# 显示内部查询(系统查询)
psql -d mydb -E

用户和权限管理

创建和管理用户

-- 创建用户(角色)
CREATE USER appuser WITH PASSWORD 'secure_password';

-- 创建无登录权限的角色
CREATE ROLE admin_role;

-- 更改用户
ALTER USER appuser WITH PASSWORD 'new_password';

-- 创建超级用户
CREATE USER superuser_name WITH PASSWORD 'password' SUPERUSER;

-- 列出用户
\du

-- 删除用户
DROP USER appuser;

授予权限

-- 授予数据库使用权限
GRANT USAGE ON SCHEMA public TO appuser;

-- 授予表权限
GRANT SELECT, INSERT, UPDATE, DELETE ON users TO appuser;

-- 授予所有权限
GRANT ALL PRIVILEGES ON users TO appuser;

-- 授予序列权限(用于自动递增)
GRANT USAGE, SELECT ON SEQUENCE users_id_seq TO appuser;

-- 授予所有表权限
GRANT SELECT ON ALL TABLES IN SCHEMA public TO appuser;

-- 为未来表设置默认权限
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO appuser;

-- 查看权限
\dp users
\dp+ users

行级安全性(RLS)

-- 在表上启用 RLS
ALTER TABLE users ENABLE ROW LEVEL SECURITY;

-- 创建策略
CREATE POLICY user_policy ON users
  USING (id = current_user_id());  # 这需要实现

-- 查看策略
\d+ users

高级 psql 功能

元命令技巧

# 详细显示最后错误
\errverbose

# 执行计时
\timing

# 回显发送到服务器的所有命令
\set ECHO all

# 列出所有变量
\set

# 查看特定变量
\echo :DBNAME

# 动态查询执行
\set query 'SELECT * FROM users WHERE id = ' :user_id
:query;

提示自定义

# 设置自定义提示
psql -v PROMPT1='user@db> '
psql -v PROMPT1='%/%R%# '   # database/role# 

# 在 .psqlrc 中
\set PROMPT1 '%n@%m:%>/%/ %R%# '
\set PROMPT2 '> '
\set PROMPT3 '>> '

函数和过程管理

-- 列出函数
\df

-- 显示函数源代码
\df+ function_name

-- 创建函数
CREATE OR REPLACE FUNCTION get_user(user_id INT)
RETURNS TABLE(id INT, name TEXT, email TEXT) AS $$
BEGIN
  RETURN QUERY
  SELECT u.id, u.name, u.email FROM users u WHERE u.id = user_id;
END;
$$ LANGUAGE plpgsql;

-- 执行函数
SELECT * FROM get_user(1);

-- 存储过程(无返回值)
CREATE OR REPLACE PROCEDURE archive_old_records()
AS $$
BEGIN
  INSERT INTO archived_users
  SELECT * FROM users WHERE created_at < now() - interval '1 year';
  DELETE FROM users WHERE created_at < now() - interval '1 year';
  COMMIT;
END;
$$ LANGUAGE plpgsql;

-- 调用过程
CALL archive_old_records();

触发器和事件

-- 创建触发器函数
CREATE OR REPLACE FUNCTION update_user_timestamp()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = CURRENT_TIMESTAMP;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 创建触发器
CREATE TRIGGER user_update_timestamp
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_user_timestamp();

-- 查看触发器
\d+ users

-- 删除触发器
DROP TRIGGER user_update_timestamp ON users;

备份和恢复

数据库备份策略

# 完整数据库备份(自定义格式)
pg_dump -d production_db -Fc -j 4 > backup.dump

# 压缩备份
pg_dump -d production_db -Fc -Z 9 > backup.dump

# 并行备份(大型数据库更快)
pg_dump -d production_db -Fd -j 4 -f backup_dir

# 备份特定模式
pg_dump -d production_db -n public -n app > schemas.sql

# 自定义格式备份(允许选择性恢复)
pg_dump -d production_db -Fc > backup.dump

# 查看备份内容
pg_restore -l backup.dump | less

# 恢复特定表
pg_restore -d restored_db -t users backup.dump

# 列出可用备份
pg_dump -U postgres -l -w postgres

时间点恢复

# 完整备份
pg_dump -d mydb > base_backup.sql

# 启用 WAL 归档(在 postgresql.conf 中)
wal_level = replica
archive_mode = on
archive_command = 'cp %p /archive/%f'

# 恢复到时间点
pg_restore -d recovered_db base_backup.sql
# 然后应用 WAL 文件直到目标时间

常见模式和示例

连接池脚本

#!/bin/bash
# 使用 psql 的简单连接池

MAX_CONNECTIONS=10
CONNECTION_POOL=()

for i in {1..$MAX_CONNECTIONS}; do
  (
    while true; do
      psql -d mydb -c "SELECT 1"
      sleep 60
    done
  ) &
  CONNECTION_POOL+=($!)
done

# 保持脚本运行
wait

数据库健康检查

-- health_check.sql
SELECT 
  'PostgreSQL Version' AS check_type,
  version() AS result
UNION ALL
SELECT 
  'Database Size',
  pg_size_pretty(pg_database_size(current_database()))
UNION ALL
SELECT 
  'Active Connections',
  count(*)::text
FROM pg_stat_activity
UNION ALL
SELECT 
  'Cache Hit Ratio',
  ROUND(sum(heap_blks_hit)::numeric / (sum(heap_blks_hit) + sum(heap_blks_read)), 4)::text
FROM pg_statio_user_tables;

自动化维护

#!/bin/bash
# 每周维护脚本

DATABASES=$(psql -t -c "SELECT datname FROM pg_database WHERE datistemplate = false AND datname != 'postgres';")

for db in $DATABASES; do
  echo "Analyzing $db..."
  psql -d "$db" -c "ANALYZE;"
  
  echo "Vacuuming $db..."
  psql -d "$db" -c "VACUUM;"
  
  echo "Reindexing $db..."
  psql -d "$db" -c "REINDEX DATABASE \"$db\";"
done

最佳实践

  1. 使用连接池 - 对于应用程序,交互式 psql 不需要
  2. 启用 SSL/TLS - 生产环境中始终使用加密连接
  3. 使用 .pgpass - 避免在脚本中硬编码密码
  4. 设置 ON_ERROR_STOP - 在脚本中防止错误后继续
  5. 使用事务 - 在显式事务中包装相关操作
  6. 策略性索引 - 分析查询计划,在频繁过滤/连接列上创建索引
  7. 监控性能 - 定期检查慢查询和表大小
  8. 定期备份 - 使用自定义格式的 pg_dump 以获得灵活性
  9. 使用模式 - 逻辑组织数据库对象
  10. 文档化权限 - 保持清晰的用户角色和权限记录
  11. 测试恢复 - 定期练习从备份恢复
  12. 使用参数化查询 - 在应用程序中防止 SQL 注入
  13. 监控锁 - 在 pg_stat_activity 中检查阻塞查询
  14. 维护统计 - 定期运行 ANALYZE 以优化查询

提示和技巧

快速导航

# 连接并在一行中执行
psql -d mydb -c "SELECT COUNT(*) FROM users;"

# 执行文件并退出
psql -d mydb -f script.sql

# 静默模式(最小输出)
psql -q -d mydb -c "SELECT * FROM users LIMIT 1;"

# 管道输出到其他命令
psql -d mydb -t -c "SELECT name FROM users;" | sort | uniq

# 验证连接而不执行命令
psql -d mydb -c ""

有用的 .psqlrc 快捷方式

# 添加到 ~/.psqlrc 以便捷快捷方式
\set dbsize 'SELECT pg_size_pretty(pg_database_size(current_database()))'
\set uptime 'SELECT now() - pg_postmaster_start_time() AS uptime'
\set psql_version 'SELECT version()'
\set table_sizes 'SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'\''.\'\'||tablename)) FROM pg_tables ORDER BY pg_total_relation_size(schemaname||'\''.\'\'||tablename) DESC'

# 在 psql 中使用:
# :dbsize
# :table_sizes

处理大型结果集

# 为大型结果设置分页器
\pset pager always

# 使用 LIMIT 测试
SELECT * FROM huge_table LIMIT 10;

# 使用 OFFSET 分页
SELECT * FROM users LIMIT 10 OFFSET 0;
SELECT * FROM users LIMIT 10 OFFSET 10;

# 将结果获取到文件而非终端
\copy (SELECT * FROM huge_table) TO huge_export.csv;

故障排除

连接问题

# 详细连接诊断
psql -d mydb -v verbose=on --echo-queries

# 检查连接设置
psql --version
psql -d postgres -c "SHOW password_encryption;"

# TCP/IP 连接性测试
psql -h hostname -d postgres -U postgres -c "SELECT 1;"

常见错误消息

FATAL: password authentication failed
  → 检查密码、用户存在、.pgpass 权限正确(600)

FATAL: no pg_hba.conf entry for host
  → 数据库服务器的 pg_hba.conf 需要连接规则

FATAL: database "name" does not exist
  → 创建数据库或检查数据库名称拼写

ERROR: permission denied for schema
  → 授予用户模式使用权限

ERROR: syntax error
  → 检查 SQL 语法,使用 \h 获取命令帮助

性能问题

-- 查找慢查询
SELECT * FROM pg_stat_statements 
ORDER BY total_time DESC 
LIMIT 10;

-- 检查缺失索引
SELECT schemaname, tablename, attname 
FROM pg_stat_user_tables, pg_attribute 
WHERE pg_stat_user_tables.relid = pg_attribute.attrelid
AND seq_scan > 0;

-- 检查缓存效率
SELECT 
  sum(heap_blks_read) as heap_read,
  sum(heap_blks_hit)  as heap_hit,
  sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) AS ratio
FROM pg_statio_user_tables;

高级配置

性能调优参数

# 在 ~/.psqlrc 中
\set HISTSIZE 10000
\pset pager always
\pset null '[NULL]'
\pset linestyle unicode

# 默认环境变量
export PGHOST=localhost
export PGPORT=5432
export PGUSER=postgres
export PGDATABASE=mydb
export PGPASSFILE=$HOME/.pgpass

输出格式比较

-- 对齐(默认)
\pset format aligned

-- CSV
\pset format csv
\copy (SELECT * FROM users) TO STDOUT WITH (FORMAT CSV);

-- HTML
\pset format html
SELECT * FROM users LIMIT 5;

-- LaTeX
\pset format latex
SELECT * FROM users LIMIT 5;

-- 扩展(垂直)
\x
SELECT * FROM users LIMIT 1;

资源和文档

总结

psql 是一个强大、灵活的命令行工具,用于 PostgreSQL 数据库管理和开发。关键优势:

  • 交互式 REPL 用于即时查询反馈
  • 强大的元命令用于对象检查和管