PostgreSQL 常用命令速查:MySQL 用户平滑上手,psql 元命令 + 库表管理 + 运维排查一篇通

📝 摘要 :MySQL 用户第一次进 psql 就懵------SHOW DATABASESUSE 全不认。本文把 PostgreSQL 最常用命令一篇讲清:psql 反斜杠元命令、库 / schema / 表管理、用户权限、\copypg_dump 导入导出、运维排查三板斧(pg_stat_activity 看连接、pg_terminate_backend 杀查询、pg_stat_statements 抓慢 SQL),每类附 MySQL 对照。
MySQL 老司机第一次连上 PostgreSQL,通常三秒破防:

SHOW DATABASES; ------ 报错;

USE mydb; ------ 还是报错;

SHOW TABLES; ------ 继续报错。

那一刻的心理活动是:「这数据库怎么啥都不会?」

------不是它不会,是 PostgreSQL 把这些操作交给了 psql 的反斜杠元命令。搞懂这套「暗号」,你就从「啥都报错」瞬间切换到「行云流水」。这篇就是那本暗号手册。

一、连接与 psql 起步

bash 复制代码
# 基本连接:-h 主机 -p 端口(默认5432) -U 用户 -d 库名
psql -h 127.0.0.1 -p 5432 -U postgres -d mydb

# 也可以用连接串(URI)
psql "postgresql://user:password@127.0.0.1:5432/mydb"

# 不进交互界面,直接跑一条 SQL 拿结果(运维 / 脚本最常用)
psql -h 127.0.0.1 -U postgres -d mydb -c "SELECT count(*) FROM app.account;"

# 数据库跑在 Docker 里时,套一层 docker exec 即可
docker exec -it <容器名> psql -U postgres -d mydb -c "SELECT ...;"

进到 psql 交互界面后,先记住这几个「保命键」:

命令 作用
\? psql 元命令帮助(反斜杠命令一览)
\h SQL 语法帮助,如 \h SELECT\h CREATE TABLE
\conninfo 当前连的哪个库、哪个用户、哪个端口
\q 退出

⚠️ 关键分工:\h 查的是 SQL 语句 语法,\? 查的是 psql 自己的反斜杠命令。两个帮助别搞混。

二、psql 元命令速查(最核心,最 PG 特色)

MySQL 里的 SHOW xxx 在 PostgreSQL 里基本都对应一个反斜杠命令。这张对照表是全文最该收藏的:

psql 元命令 作用 MySQL 对应
\l 列出所有数据库 SHOW DATABASES;
\c dbname 切换数据库 USE dbname;
\dt 列出当前 schema 的表 SHOW TABLES;
\d 表名 查看表结构 DESC 表名;
\d+ 表名 表结构 + 大小 + 详情 SHOW CREATE TABLE(近似)
\dn 列出所有 schema ------
\du 列出所有角色 / 用户 SELECT user FROM mysql.user;
\di / \dv / \df 列出索引 / 视图 / 函数 ------
\dt *.* 跨 schema 列表 ------
\x 切换「竖排显示」(宽表神器) \G(行尾)
\timing 开关「显示每条 SQL 耗时」 ------
\e 用编辑器写 SQL ------
\i 文件 执行 SQL 脚本文件 source 文件
\! 命令 执行 shell 命令 \! 命令

几个高频到必须形成肌肉记忆的:

  • \x :字段多的宽表,横着看到吐血?敲一下 \x,切成一行一个字段的竖排,瞬间清爽(等价于 MySQL 的行尾 \G)。
  • \timing:开一次,之后每条 SQL 都自动报耗时,随手测性能。
  • \dtS / \dS :命令加大写 S连系统对象一起显示(S = System),排查系统表时用得上。

三、库 / schema / 表管理(DDL)

这块和标准 SQL 基本一致,但有个 MySQL 用户绕不开的概念差异------PostgreSQL 多了一层 schema

text 复制代码
MySQL:   实例 → database(≈schema) → table
Postgres:实例 → database → schema(默认 public) → table
sql 复制代码
-- 建库
CREATE DATABASE mydb;

-- 建 schema(一个库下可分多个命名空间)
CREATE SCHEMA app;

-- 建表(注意自增列写法和 MySQL 不同)
CREATE TABLE app.account (
    id          BIGSERIAL PRIMARY KEY,   -- 自增:SERIAL/BIGSERIAL,或 GENERATED ... AS IDENTITY
    username    VARCHAR(64) NOT NULL,
    balance     NUMERIC(12,2) DEFAULT 0, -- 金额用 NUMERIC,别用 float
    created_at  TIMESTAMPTZ DEFAULT now()
);

-- 改表
ALTER TABLE app.account ADD COLUMN status SMALLINT DEFAULT 0;

-- 搜索路径:设了之后可以不写 schema 前缀直接用表名
SET search_path TO app, public;

search_path 就是 PostgreSQL 版的「默认 schema」。设成 app 后,SELECT * FROM account 就等价于 app.account------省去每次写 schema 前缀。

四、用户与权限

PostgreSQL 里用户(USER)本质就是带登录权限的角色(ROLE)CREATE USER = CREATE ROLE ... LOGIN

sql 复制代码
-- 建用户
CREATE USER app_rw WITH PASSWORD 'secret';

-- 授权:库、schema、表逐层给
GRANT CONNECT ON DATABASE mydb TO app_rw;
GRANT USAGE ON SCHEMA app TO app_rw;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app TO app_rw;

-- 让「以后新建的表」也自动带上权限(否则新表要重新授权)
ALTER DEFAULT PRIVILEGES IN SCHEMA app
    GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_rw;

-- 改密码(psql 内推荐用 \password,密码不会明文进历史)
\password app_rw

一个经典坑:给了 ALL TABLES 权限,但之后新建的表 app_rw 又没权限了。解药就是上面的 ALTER DEFAULT PRIVILEGES------给「未来的表」预授权。

五、导入导出

这里有个 MySQL 用户最容易踩的坑:\copyCOPY 长得像,权限却完全不同。

命令 在哪执行 读写哪台机器的文件 权限
\copy(psql 元命令) psql 客户端 你本地的文件 普通用户即可
COPY(SQL 语句) 服务端 数据库服务器上的文件 需超级用户 / 特定角色
sql 复制代码
-- 导出一张表到本地 CSV(客户端,最常用)
\copy app.account TO '/tmp/account.csv' WITH CSV HEADER

-- 从本地 CSV 导入
\copy app.account FROM '/tmp/account.csv' WITH CSV HEADER

-- 导出查询结果
\copy (SELECT id, username FROM app.account WHERE status = 0) TO '/tmp/act.csv' CSV HEADER

整库 / 逻辑备份用 pg_dump(命令行,不是 psql 内):

bash 复制代码
# 自定义格式备份(推荐,支持并行 + 选择性恢复)
pg_dump -h 127.0.0.1 -U postgres -d mydb -Fc -f mydb.dump

# 恢复
pg_restore -h 127.0.0.1 -U postgres -d mydb_new mydb.dump

# 纯 SQL 文本备份(可读、可 grep)
pg_dump -h 127.0.0.1 -U postgres -d mydb -f mydb.sql

# 备份所有库 + 全局角色
pg_dumpall -h 127.0.0.1 -U postgres -f all.sql

图形化迁移(DBeaver)的姿势可参考 《MySQL 数据库迁移/复制实战:DBeaver 图形化 + 命令行两种方式》,思路在 PostgreSQL 上同样适用。

六、运维与排查(线上救命)

这是线上真正救命的部分。MySQL 的 SHOW PROCESSLIST + KILL 那套,在 PostgreSQL 里换了套写法。先记「三板斧」------看连接(pg_stat_activity)、杀查询(pg_terminate_backend)、抓慢 SQL(pg_stat_statements,够应付大多数现场;再往下的抓锁、看大小、EXPLAIN、VACUUM、调参兜底是进阶补充。整条排查路径串起来是这样:
#mermaid-svg-8V6G3oj9va3RB4Ot{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8V6G3oj9va3RB4Ot .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8V6G3oj9va3RB4Ot .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8V6G3oj9va3RB4Ot .error-icon{fill:#552222;}#mermaid-svg-8V6G3oj9va3RB4Ot .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8V6G3oj9va3RB4Ot .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8V6G3oj9va3RB4Ot .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8V6G3oj9va3RB4Ot .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8V6G3oj9va3RB4Ot .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8V6G3oj9va3RB4Ot .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8V6G3oj9va3RB4Ot .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8V6G3oj9va3RB4Ot .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8V6G3oj9va3RB4Ot .marker.cross{stroke:#333333;}#mermaid-svg-8V6G3oj9va3RB4Ot svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8V6G3oj9va3RB4Ot p{margin:0;}#mermaid-svg-8V6G3oj9va3RB4Ot .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8V6G3oj9va3RB4Ot .cluster-label text{fill:#333;}#mermaid-svg-8V6G3oj9va3RB4Ot .cluster-label span{color:#333;}#mermaid-svg-8V6G3oj9va3RB4Ot .cluster-label span p{background-color:transparent;}#mermaid-svg-8V6G3oj9va3RB4Ot .label text,#mermaid-svg-8V6G3oj9va3RB4Ot span{fill:#333;color:#333;}#mermaid-svg-8V6G3oj9va3RB4Ot .node rect,#mermaid-svg-8V6G3oj9va3RB4Ot .node circle,#mermaid-svg-8V6G3oj9va3RB4Ot .node ellipse,#mermaid-svg-8V6G3oj9va3RB4Ot .node polygon,#mermaid-svg-8V6G3oj9va3RB4Ot .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8V6G3oj9va3RB4Ot .rough-node .label text,#mermaid-svg-8V6G3oj9va3RB4Ot .node .label text,#mermaid-svg-8V6G3oj9va3RB4Ot .image-shape .label,#mermaid-svg-8V6G3oj9va3RB4Ot .icon-shape .label{text-anchor:middle;}#mermaid-svg-8V6G3oj9va3RB4Ot .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8V6G3oj9va3RB4Ot .rough-node .label,#mermaid-svg-8V6G3oj9va3RB4Ot .node .label,#mermaid-svg-8V6G3oj9va3RB4Ot .image-shape .label,#mermaid-svg-8V6G3oj9va3RB4Ot .icon-shape .label{text-align:center;}#mermaid-svg-8V6G3oj9va3RB4Ot .node.clickable{cursor:pointer;}#mermaid-svg-8V6G3oj9va3RB4Ot .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8V6G3oj9va3RB4Ot .arrowheadPath{fill:#333333;}#mermaid-svg-8V6G3oj9va3RB4Ot .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8V6G3oj9va3RB4Ot .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8V6G3oj9va3RB4Ot .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8V6G3oj9va3RB4Ot .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8V6G3oj9va3RB4Ot .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8V6G3oj9va3RB4Ot .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8V6G3oj9va3RB4Ot .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8V6G3oj9va3RB4Ot .cluster text{fill:#333;}#mermaid-svg-8V6G3oj9va3RB4Ot .cluster span{color:#333;}#mermaid-svg-8V6G3oj9va3RB4Ot div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8V6G3oj9va3RB4Ot .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8V6G3oj9va3RB4Ot rect.text{fill:none;stroke-width:0;}#mermaid-svg-8V6G3oj9va3RB4Ot .icon-shape,#mermaid-svg-8V6G3oj9va3RB4Ot .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8V6G3oj9va3RB4Ot .icon-shape p,#mermaid-svg-8V6G3oj9va3RB4Ot .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8V6G3oj9va3RB4Ot .icon-shape .label rect,#mermaid-svg-8V6G3oj9va3RB4Ot .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8V6G3oj9va3RB4Ot .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8V6G3oj9va3RB4Ot .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8V6G3oj9va3RB4Ot :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 某条 SQL 跑太久
会话互相卡住
反复慢 · 找共性
线上出问题:慢 / 卡 / 连接满
① 看谁在跑

pg_stat_activity

(对标 SHOW PROCESSLIST)
什么现象?
② 杀查询

先 pg_cancel_backend,不行再 pg_terminate_backend

雪崩时按 库 / 时长 / ILIKE 批量杀
抓锁

pg_blocking_pids(pid)

看谁挡着谁
③ 抓慢 SQL

pg_stat_statements

按 total_exec_time 排序
EXPLAIN (ANALYZE, BUFFERS)

Seq Scan → 缺索引

CREATE INDEX CONCURRENTLY 不锁表
兜底止血

statement_timeout 封顶

max_parallel_workers_per_gather=0

ALTER SYSTEM + pg_reload_conf 免重启
治本

VACUUM 治膨胀 · 加索引 · OLAP 别塞 OLTP

图:PostgreSQL 运维排查三板斧流程------先用 pg_stat_activity 看谁在跑,按现象分流到「杀查询 / 抓锁 / 抓慢 SQL」,EXPLAIN 定位缺索引,statement_timeout 等参数兜底止血,最后 VACUUM 与加索引治本。

6.1 看谁在跑、看连接数(对标 SHOW PROCESSLIST)

sql 复制代码
-- 当前所有会话 / 正在跑的 SQL
SELECT pid, usename, state, wait_event_type,
       now() - query_start AS duration, query
FROM pg_stat_activity
WHERE state <> 'idle'
ORDER BY duration DESC;

-- 连接数总览(排查连接打满)
SELECT count(*), state FROM pg_stat_activity GROUP BY state;

⚠️ query 字段有两个必知的坑(实战里一眼就会撞上):

  1. SQL 显示不全query 默认被 track_activity_query_size 截断到 1024 字节 ,长 SQL 直接被砍一半。要看全,调大它(改 postgresql.conf需重启 ):

    conf 复制代码
    track_activity_query_size = 8192   # 或更大
  2. SQL 里出现 $1$2::timestamp :这是预编译 / 参数化查询 (ORM、JDBC PreparedStatement 常见)的占位符------pg_stat_activity 按设计只存参数化后的语句、不存实际参数值 ,所以你看到的是 $1 而不是真实值。想拿到带参数值的完整 SQL,得走日志 而不是这张视图:

    conf 复制代码
    log_min_duration_statement = 1000   # 记录 >1s 的慢语句
    log_parameter_max_length = -1       # PG13+:日志里完整打印绑定参数值($1 = '...')

    然后去 PostgreSQL 日志里看,慢语句会连 parameters: $1 = 'xxx' 一起打出来。

另外,state = 'idle' 的行,query 显示的是它最后一次执行 的语句(不是正在跑)------排查"当前在跑什么"记得 WHERE state <> 'idle' 过滤掉。

6.2 杀查询 / 杀连接(对标 KILL)

sql 复制代码
-- 温柔取消一条正在跑的 SQL(只取消查询,连接保留)
SELECT pg_cancel_backend(12345);   -- 12345 = 上面查到的 pid

-- 强制杀掉整个连接(连接一起断)
SELECT pg_terminate_backend(12345);

记忆法:cancel = 撤销这条 SQL(相当于 Ctrl+C),terminate = 掐断整个连接。优先 cancel,不行再 terminate。

慢查询并发把 CPU 打爆时,一个个 pid 杀太慢,直接批量杀------按库、时长、语句类型筛出来一次清掉:

sql 复制代码
-- 一键杀掉某库里所有「跑超过 30 秒的 SELECT」
SELECT pid, pg_terminate_backend(pid), left(query, 60) AS killed
FROM pg_stat_activity
WHERE datname = 'mydb'                       -- 只动这个库
  AND state = 'active'
  AND now() - query_start > interval '30 seconds'
  AND query ILIKE 'SELECT%'                  -- 只杀读查询,不碰写入 / INSERT
  AND pid <> pg_backend_pid();               -- 别把执行这条命令的自己也杀了

三个安全阀缺一不可:datname= 限定库、ILIKE 'SELECT%' 只杀读、pid <> pg_backend_pid() 不误杀自身。线上慢查询雪崩时,这一条比逐个 pg_terminate_backend(pid) 快得多。注意:若是前端页面(如某 dashboard)自动重发的查询,杀完会立刻又冒出来,得先让人关掉页面。

6.3 抓锁(谁卡住了谁)

sql 复制代码
-- 阻塞关系:谁在等锁、被谁挡着
SELECT blocked.pid AS blocked_pid, blocked.query AS blocked_query,
       blocking.pid AS blocking_pid, blocking.query AS blocking_query
FROM pg_stat_activity blocked
JOIN pg_stat_activity blocking
     ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
WHERE blocked.wait_event_type = 'Lock';

pg_blocking_pids(pid) 是排查锁等待的神器------直接告诉你「这个被卡的会话,是被哪些会话挡着的」。

6.4 看大小(库、表、索引)

sql 复制代码
-- 各库大小
SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database ORDER BY pg_database_size(datname) DESC;

-- 当前库里最大的 10 张表(含索引)
SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) AS total
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;

6.5 抓慢 SQL(pg_stat_statements)

PostgreSQL 抓慢 SQL 的标配是 pg_stat_statements 扩展------按累计耗时排序,谁最费时间一目了然

sql 复制代码
-- 一次性安装(需在 postgresql.conf 的 shared_preload_libraries 里加它并重启)
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

-- 找出最耗时的 Top 10 SQL
SELECT queryid, calls, total_exec_time, mean_exec_time, query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;

⚠️ 版本坑total_exec_time / mean_exec_timePG13+ 的列名;PG12 及以前叫 total_time / mean_time,直接跑上面这条会报「列不存在」。老版本把两处列名换掉即可。

6.6 EXPLAIN:看执行计划(慢 SQL 的下一步)

pg_stat_statements 揪出慢 SQL 后,下一步就是 EXPLAIN 看它到底慢在哪------PostgreSQL 的 EXPLAIN 比 MySQL 的信息量大得多:

sql 复制代码
-- 只看计划(不执行,看的是优化器的"估算")
EXPLAIN SELECT * FROM app.account WHERE username = 'tom';

-- 真正执行并给出「实际耗时 + 实际行数」,排查必用
EXPLAIN ANALYZE SELECT * FROM app.account WHERE username = 'tom';

-- 加上缓存命中情况(看走没走 shared_buffers / page cache),最完整
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM app.account WHERE username = 'tom';

怎么读:

  • Seq Scan(全表扫描) 出现在大表上 = 危险信号,通常意味着缺索引 ;理想是走 Index Scan / Index Only Scan
  • cost=0.00..25.88:优化器估算的启动成本...总成本(相对值,越大越贵)。
  • rows= 估算行数 vs actual ... rows= 实际行数 :两者差距悬殊,说明统计信息过期 ,该 ANALYZE 更新统计了。
  • actual time= / loops= :真实耗时和循环次数,EXPLAIN ANALYZE 才有。

确认是「大表缺索引」导致的 Seq Scan 后,补索引别直接 CREATE INDEX ------它会加锁、写阻塞整张表。线上大表用 CREATE INDEX CONCURRENTLY ON app.account(username);:不锁表、后台慢慢建(代价是更耗时,且失败会残留一个 INVALID 索引,需 DROP 掉重建)。
⚠️ 一个能捅娄子的坑EXPLAIN ANALYZE真的会执行语句 的!对 SELECT 无所谓,但对 INSERT/UPDATE/DELETE------数据真的会被改。要分析写语句,务必包在事务里回滚:

sql 复制代码
BEGIN;
EXPLAIN ANALYZE UPDATE app.account SET status = 1 WHERE id = 100;
ROLLBACK;   -- 只看计划,不落地

6.7 VACUUM 与 ANALYZE(PostgreSQL 独有的必修课)

PostgreSQL 的 MVCC 机制会留下「死元组」,需要 VACUUM 回收------这是 MySQL 用户没有的概念,但不懂它迟早被表膨胀坑到

sql 复制代码
VACUUM ANALYZE app.account;   -- 回收死元组 + 更新统计信息(日常)
VACUUM FULL app.account;      -- 彻底重整、真正释放磁盘,但会锁表,谨慎用
ANALYZE app.account;          -- 只更新统计信息,帮优化器选对执行计划

怎么判断一张表「该不该 VACUUM / ANALYZE」------看死元组多不多、上次自动维护是什么时候:

sql 复制代码
-- 死元组数、上次 autovacuum / autoanalyze 时间,按死元组降序
SELECT relname, n_live_tup, n_dead_tup, last_autovacuum, last_analyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC;

n_dead_tup(死元组)居高不下、last_autovacuum 半天没更新,就是 autovacuum 没跟上、表在膨胀的信号------大表尤其要盯。上一节 EXPLAIN 里「估算行数 vs 实际行数差很大」也常源于此(统计信息过期),补一次 ANALYZE 即可。
平时有 autovacuum 自动兜底,一般不用手动。但大批量删除 / 更新后表膨胀明显时,可手动 VACUUM;想真正把磁盘还给系统,才用会锁表的 VACUUM FULL

6.8 运行时调参与兜底(改配置不重启 + 防慢查询拖垮机器)

线上出问题时,很多参数不用重启就能改 ------ALTER SYSTEM 写进配置、再 pg_reload_conf() 让它生效:

sql 复制代码
-- 通用套路:改参数 → 重载,立即生效(对「可 reload」的参数有效)
ALTER SYSTEM SET log_min_duration_statement = '1000';  -- 记录 >1s 的慢语句
SELECT pg_reload_conf();                                -- 重读配置,无需重启
SHOW log_min_duration_statement;                        -- 确认生效值

⚠️ ALTER SYSTEM 改的参数分两类:标了 context = postmaster 的(如 shared_preload_libraries仍要重启 才生效;大多数运行时参数(日志、超时、并行度)pg_reload_conf() 就够。这正好补上第六节开头「改 postgresql.conf 需重启」的另一条路------能 reload 的别重启。

几条线上救命的兜底参数:

sql 复制代码
-- 1. 语句超时:不让任何查询无限跑(一条几分钟的全表扫就足以拖死机器)
--    只挂在某个库上,别设全局,免得误杀别的库的正常长事务
ALTER DATABASE mydb SET statement_timeout = '60s';

-- 2. 关掉并行全表扫:2~4 核小机器上,一条慢查询拉起 N 个 parallel worker 一起刷盘 = 自杀
--    关了之后慢查询最多占一个核、盘上只有一路顺序读
ALTER SYSTEM SET max_parallel_workers_per_gather = 0;
SELECT pg_reload_conf();

-- 3. 慢查询日志(配 6.1 的截断说明一起用):运行时开,事后 grep 日志拿参数化 SQL 全文
ALTER SYSTEM SET log_min_duration_statement = '2000';
SELECT pg_reload_conf();

这是「治标三件套」:statement_timeout 给查询封顶、max_parallel_workers_per_gather = 0 防单条查询把多核连盘一起打满、慢日志留证据。治本仍要回到加索引 / 删旧数据 / 换列存------OLAP 分析查询别硬塞进 OLTP 库

七、MySQL → PostgreSQL 高频踩坑

从 MySQL 转过来,这几个坑几乎人人踩一遍:

真相
双引号当字符串用 PG 里单引号才是字符串"xxx"标识符 (列名 / 表名)。WHERE name = "abc" 会报「列 abc 不存在」
标识符大小写 未加引号的标识符 PG 一律转小写"MyTable" 加引号才区分大小写,且以后都得带引号
SHOW CREATE TABLE 没有 \d 表名 看结构,或 pg_dump -t 表名 --schema-only 拿建表语句
自增 不是 AUTO_INCREMENT,用 SERIAL/BIGSERIALGENERATED ALWAYS AS IDENTITY
字符串拼接 用 `
反引号 PG 不认 MySQL 的 col,标识符用双引号
端口 / 库切换 默认端口 5432 (不是 3306);切库用 \c 而不是 USE
LIMIT 分页 LIMIT n OFFSET m 一致,这个不用改
EXPLAIN ANALYZE 会真执行 MySQL 的 EXPLAIN 不执行;PG 的 EXPLAIN ANALYZE 真跑,写语句要 BEGIN..ROLLBACK 包起来

八、总结:一张随身速查卡

最后浓缩成一张「进 psql 先敲这几个」的卡片:

text 复制代码
连接排障:  \conninfo  \l  \c db  \dt  \d 表  \du  \dn
显示优化:  \x(竖排)  \timing(耗时)  \dtS(含系统对象)
跑一条 SQL:psql -d db -c "SQL"   (Docker 里套 docker exec)
看连接:    SELECT * FROM pg_stat_activity WHERE state<>'idle';
杀查询:    SELECT pg_cancel_backend(pid);   / pg_terminate_backend(pid)
批量杀:    ...pg_terminate_backend(pid)... WHERE now()-query_start>'30s' AND query ILIKE 'SELECT%' AND pid<>pg_backend_pid()
抓锁:      pg_blocking_pids(pid)
看大小:    pg_size_pretty(pg_database_size / pg_total_relation_size)
抓慢SQL:   pg_stat_statements ORDER BY total_exec_time DESC
看计划:    EXPLAIN (ANALYZE, BUFFERS) SQL   (写语句包 BEGIN..ROLLBACK)
建索引:    CREATE INDEX CONCURRENTLY ...   (大表不锁表)
调参兜底:  ALTER SYSTEM SET xxx + SELECT pg_reload_conf();(免重启)
           statement_timeout / max_parallel_workers_per_gather=0
查膨胀:    SELECT n_dead_tup,last_autovacuum FROM pg_stat_user_tables
维护:      VACUUM ANALYZE   /  VACUUM FULL(锁表慎用)
备份:      pg_dump -Fc  /  pg_restore  /  \copy CSV

一句话记住 PostgreSQL 和 MySQL 最大的手感差异:

MySQL 的 SHOW / USE / DESC / KILL,在 PostgreSQL 里换成了「反斜杠元命令 + pg_ 系统视图 + 函数」。 暗号对上了,剩下的就是标准 SQL,转过来一点不难。

你从 MySQL 转 PostgreSQL,还踩过哪些坑?欢迎评论区补充。


延伸阅读


🏷️ 标签PostgreSQL psql 命令速查 数据库运维 SQL MySQL 对比

相关推荐
祝威廉4 小时前
四条语句跑完机器学习:让模型成为一个 SQL 函数
人工智能·sql·机器学习
han_hanker5 小时前
SQL语法 , BETWEEN ... AND ...,比较运算符
前端·javascript·sql
爱喝水的鱼丶5 小时前
SAP-ABAP:SELECT大数据量查询性能调优——避免嵌套循环、减少数据库交互的核心方案
开发语言·数据库·sql·性能优化·sap·abap·erp
三8445 小时前
get方法/post方法/SQL注入文字型/数字型
数据库·sql·mysql
Lucifer三思而后行17 小时前
Veeam 备份 Oracle RAC 失败,是归档删除脚本的锅!
sql
互联网中的一颗神经元21 小时前
小白python入门 - 25. SQL 与表设计入门
数据库·python·sql
AI人工智能集结号1 天前
AI回答采集:基于PostgreSQL JSONB的原始数据存储与可追溯性方案
数据库·人工智能·postgresql
IvorySQL1 天前
PG 日报|查询优化器重大修复,支持更多复杂 SQL 优化
数据库·人工智能·postgresql·开源
桐薇全肯定1 天前
MySQL学生成绩管理系统实战操作
java·数据库·sql