文档说明
1.适用版本:PostgreSQL 12/13/14/15/16/18 源码编译/二进制部署
2.巡检范围:服务器主机资源、数据库实例状态、连接、锁、长事务、慢SQL、表/索引膨胀、WAL主从、权限、自动清理等全维度
3.使用场景:日常定时巡检、故障排查、上线前核查、月度运维报告
4.规范:每条巡检项包含执行命令/SQL、正常标准、异常处理方案
1.1 主机信息巡检(root执行)
1.1.1 CPU检查
前置工具安装
|
yum install -y sysstat
# Ubuntu
apt install -y sysstat
|
查看空闲CPU
|
# 空闲CPU占比
mpstat | sed -n '3,$p' | awk -F' ' '{print $13}'
# 用户CPU占用
mpstat | sed -n '3,$p' | awk -F' ' '{print $12}'
# CPU核心总数
echo 'CPU CORE:' && cat /proc/cpuinfo|grep processor|wc -l
|
正常标准:空闲CPU>20%
异常处理:top -c 定位高CPU进程,终止无效长SQL会话
1.1.2. 内存检查
正常标准:空闲内存占总内存>30%
异常处理:top查看内存占用进程,清理长时间空闲数据库连接
1.1.3 磁盘空间检查
正常标准:磁盘已用空间<70%
异常处理:清理无用日志/备份,扩容磁盘
1.1.4 磁盘IO检查
|
iostat -x | sed -n '6,$p' | awk -F' ' '{print $1,$13,$14}'
|
输出字段:磁盘设备、%iowait、%util
正常标准:%util持续低于70%
异常处理:优化慢SQL、减少大批量DML、扩容高速存储
1.1.5 数据库端口监听检查
|
netstat -tanp | grep 'LISTEN' | grep '5432'
|
正常标准:tcp4、tcp6双协议正常监听5432
异常处理:
1.检查数据库是否正常启动
2.核对postgresql.conf listen_addresses、port 参数
1.1.6 PostgreSQL后台进程完整性检查
|
ps -ef | grep "checkpointer|background writer|walwriter|autovacuum launcher|archiver|stats collector|logical replication launcher|logger" | grep -v grep
|
正常标准:所有核心后台进程全部存在
异常处理:数据库异常退出,执行 systemctl restart postgresql-xx 重启实例
1.2 数据库巡检(su - postgres 登录psql执行)
1.2.1 实例基础信息、运行时长、主备标识
|
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,to_char(pg_postmaster_start_time(),'yyyy-mm-dd hh24:mi:ss') "pg_start_time(启动时间)"
,now()-pg_postmaster_start_time() "pg_running_time(运行时长)"
,version() "server_version(数据库版本)"
,(case when pg_is_in_recovery()='f' then 'primary' else 'standby' end ) as "primary_or_standby(主/备)"
;
|
正常标准:实例正常运行,无崩溃重启记录
异常处理:查看pg日志,修复配置/磁盘/内核问题后重装/重启数据库
1.2.2 读取postgresql.conf全部配置
|
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,sourceline "sourceline(行号)"
,name "para(参数名)"
,setting "value(参数值)"
from pg_file_settings
order by sourceline;
|
正常标准:内存、连接、日志、WAL参数符合业务规格
异常处理:修改$PGDATA/postgresql.conf,重载/重启数据库
1.2.3 pg_hba.conf 访问认证规则核查
|
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,line_number "line_number(行号)"
,type "type(连接类型)"
,database "database(数据库名)"
,user_name "user_name(用户名)"
,address "address(ip地址)"
,netmask "netmask(子网掩码)"
,auth_method "auth_method(认证方式)"
from pg_hba_file_rules
order by line_number;
|
正常标准:外网非本地套接字连接统一使用 scram-sha-256 认证
异常处理:编辑pg_hba.conf,重载配置生效
1.2.4 核心关键配置项核查
|
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,name
,setting
from
pg_settings a
where a.name in (
'data_directory',
'port',
'client_encoding',
'config_file',
'hba_file',
'ident_file',
'archive_mode',
'logging_collector',
'log_directory',
'log_filename',
'log_truncate_on_rotation',
'log_statement',
'log_min_duration_statement',
'max_connections',
'listen_addresses'
)
order by name;
|
正常标准:目录、端口、日志、最大连接、监听地址配置合规
异常处理:修改对应参数后重载/重启数据库
1.2.5 主从WAL同步状态
主库执行(查看备库复制流)
|
select
state "state(WAL发送状态编码)"
,sync_state "sync_state(同步状态编码)"
,round(pg_wal_lsn_diff(pg_current_wal_lsn(),replay_lsn) /(1024 * 1024),2) as "slave_latency_mb(同步延迟_MB)"
from pg_stat_replication;
|
备库执行(查看WAL接收进程)
|
select
status "status(WAl接收状态)"
,'async' "sync_state(同步状态编码)"
,sender_host "sender_host(主库IP)"
from pg_stat_wal_receiver;
|
正常标准:主库state=streaming,同步延迟<100MB;备库接收进程正常运行
异常处理:检查网络、wal_keep_size、复制槽、归档配置
1.2.6 表空间巡检
|
SELECT
to_char(now(),'yyyy-mm-dd hh24:mi:ss') AS "巡检时间",
spcname AS "Name(表空间名称)",
pg_catalog.pg_get_userbyid(spcowner) AS "Owner(拥有者)",
pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS "Size(表空间大小)"
FROM pg_catalog.pg_tablespace
ORDER BY pg_catalog.pg_tablespace_size(oid) DESC;
|
1.2.7 数据库连接数管理
总连接统计
|
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,max_conn "max_conn(最大连接数)"
,now_conn "now_conn(当前连接数)"
,max_conn - now_conn "remain_conn(剩余连接数)"
from (
select
setting::int8 as max_conn
,(select count(*) from pg_stat_activity ) as now_conn
from pg_settings
where name = 'max_connections'
) a
;
|
按数据库分组连接数
|
SELECT
datname AS "数据库名",
COUNT(*) AS "连接数"
FROM pg_stat_activity
WHERE datname IS NOT NULL
GROUP BY datname
ORDER BY COUNT(*) DESC;
|
按用户分组连接数
|
SELECT usename, COUNT(*) AS connection_count
FROM pg_stat_activity
GROUP BY usename;
|
单库空闲连接批量终止(示例库test_db)
|
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'test_db'
AND state = 'idle'
AND pid <> pg_backend_pid();
|
全局终止30分钟以上空闲连接
|
DO
$$
DECLARE
r RECORD;
BEGIN
FOR r IN (
SELECT pid
FROM pg_stat_activity
WHERE state = 'idle'
AND now() - state_change > INTERVAL '30 minutes'
AND pid <> pg_backend_pid()
) LOOP
PERFORM pg_terminate_backend(r.pid);
END LOOP;
END
$$;
|
正常标准:当前连接数<最大连接数90%
异常处理:终止长期空闲连接,业务高峰期可临时调高max_connections
1.2.8 锁表、阻塞会话完整巡检
1. 独占锁/行排他锁查询(阻塞业务核心)
|
SELECT
to_char(now(), 'yyyy-mm-dd hh24:mi:ss') AS "巡检时间",
a.relname AS "表名",
b.nspname AS "模式名",
c.rolname AS "用户名",
d.locktype AS "锁对象类型",
d.mode AS "锁模式",
d.pid AS "进程PID",
e.query AS "阻塞SQL",
age(now(), e.query_start) AS "锁持有时长"
FROM
pg_class a
INNER JOIN
pg_namespace b ON (a.relnamespace = b.oid)
INNER JOIN
pg_roles c ON (a.relowner = c.oid)
INNER JOIN
pg_locks d ON (a.oid = d.relation)
LEFT JOIN
pg_stat_activity e ON (d.pid = e.pid)
WHERE
d.mode IN ('AccessExclusiveLock', 'RowExclusiveLock')
AND e.pid <> pg_backend_pid()
ORDER BY "锁持有时长" DESC;
|
2. 批量杀掉所有独占锁会话
|
DO $$
DECLARE
rec RECORD;
BEGIN
FOR rec IN (
SELECT d.pid AS pid
FROM pg_class a
INNER JOIN pg_namespace b ON a.relnamespace = b.oid
INNER JOIN pg_roles c ON a.relowner = c.oid
INNER JOIN pg_locks d ON a.oid = d.relation
LEFT JOIN pg_stat_activity e ON d.pid = e.pid
WHERE d.mode IN ('AccessExclusiveLock', 'RowExclusiveLock')
) LOOP
PERFORM pg_terminate_backend(rec.pid);
END LOOP;
END $$;
|
3. 指定数据库批量释放锁(替换库名test_db)
|
DO $$
DECLARE
rec RECORD;
BEGIN
FOR rec IN (
SELECT d.pid AS pid, a.relname, b.nspname, c.rolname, e.query, age(now(), e.query_start) lock_duration
FROM pg_class a
INNER JOIN pg_namespace b ON a.relnamespace = b.oid
INNER JOIN pg_roles c ON a.relowner = c.oid
INNER JOIN pg_locks d ON a.oid = d.relation
LEFT JOIN pg_stat_activity e ON d.pid = e.pid
WHERE d.mode IN ('AccessExclusiveLock', 'RowExclusiveLock')
AND e.datname = 'test_db'
) LOOP
RAISE NOTICE '终止PID:% 表%.% 锁时长:%', rec.pid, rec.nspname, rec.relname, rec.lock_duration;
PERFORM pg_terminate_backend(rec.pid);
END LOOP;
END $$;
|
锁操作区分
- pg_cancel_backend(pid):仅取消当前SQL,会话保留
- pg_terminate_backend(pid):直接断开整个数据库会话,释放全部锁
正常标准:无长期AccessExclusiveLock独占锁
异常处理:确认业务无影响后批量终止阻塞PID
1.2.9 长时间空闲连接Top5(超过5分钟)
|
SELECT
TO_CHAR(NOW(), 'yyyy-mm-dd hh24:mi:ss') AS "巡检时间",
a.datname AS "数据库名",
a.pid AS "进程PID",
b.rolname AS "用户名",
a.client_addr AS "客户端IP",
TO_CHAR(a.state_change, 'yyyy-mm-dd hh24:mi:ss') AS "空闲起始时间",
a.query AS "最后执行SQL"
FROM pg_stat_activity a
INNER JOIN pg_roles b ON a.usesysid = b.oid
WHERE a.state = 'idle'
AND a.state_change < CURRENT_TIMESTAMP - INTERVAL '5 min'
ORDER BY current_timestamp-state_change DESC
LIMIT 5;
|
正常标准:无超过30分钟空闲连接
异常处理:批量终止空闲会话释放连接资源
1.2.10 长事务 Top5(idle in transaction)
|
SELECT
to_char(now(), 'yyyy-mm-dd hh24:mi:ss') AS "巡检时间",
a.datname AS "数据库名",
a.pid AS "进程PID",
b.rolname AS "用户名",
a.client_addr AS "客户端IP",
to_char(a.state_change, 'yyyy-mm-dd hh24:mi:ss') AS "事务空闲起始时间",
a.query AS "未提交事务SQL"
FROM
pg_stat_activity a
INNER JOIN
pg_roles b ON a.usesysid = b.oid
WHERE
a.state IN ('idle in transaction', 'idle in transaction (aborted)')
AND a.state_change < current_timestamp - INTERVAL '5 min'
ORDER BY
current_timestamp - a.state_change DESC
LIMIT 5;
|
正常标准:不存在超过5分钟未提交长事务
异常处理:pg_terminate_backend(pid) 终止会话,避免快照膨胀、表膨胀
1.2.11 慢SQL活跃会话Top5(执行超5分钟)
|
SELECT
to_char(now(), 'yyyy-mm-dd hh24:mi:ss') AS "巡检时间",
a.datname AS "数据库名",
a.pid AS "进程PID",
b.rolname AS "用户名",
a.client_addr AS "客户端IP",
a.wait_event_type AS "等待类型",
a.wait_event AS "等待事件",
SUBSTRING(a.query,1,200) AS "执行SQL"
FROM
pg_stat_activity a
LEFT JOIN
pg_roles b ON (a.usesysid = b.oid)
WHERE
a.state = 'active'
AND
a.state_change < current_timestamp - INTERVAL '5 min'
AND
a.datname IS NOT NULL
ORDER BY
a.state_change DESC
LIMIT 5;
|
正常标准:无执行超过5分钟的活跃SQL
异常处理:优化索引、拆分大事务、终止卡死查询
1.2.12 数据库总对象数量统计
|
select to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,current_database()
,sum(obj_num) "obj_num(总对象数)"
from (
select count(1) obj_num from pg_class
union all
select count(1) from pg_proc
) a
;
|
正常标准:单库总对象不超过5万
异常处理:清理无用临时表、废弃存储过程
1.2.13 数据表膨胀巡检
|
SELECT
to_char(now(), 'yyyy-mm-dd hh24:mi:ss') AS "巡检时间",
current_database() AS current_database,
relname AS "table_name(表名)",
schemaname AS "schema_name(模式名)",
pg_size_pretty(pg_relation_size((schemaname || '.' || relname)::regclass)) AS "table_size(表大小)",
n_dead_tup AS "n_dead_tup(无效记录数)",
n_live_tup AS "n_live_tup(有效记录数)",
to_char(
ROUND(
(n_dead_tup * 1.0 / NULLIF(n_live_tup + n_dead_tup, 0)) * 100,
2
),
'fm990.00'
) AS "dead_rate(无效记录比例%)"
FROM
pg_stat_all_tables
WHERE
(n_live_tup + n_dead_tup) <> 0
AND schemaname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
ORDER BY
(n_dead_tup * 1.0 / NULLIF(n_live_tup + n_dead_tup, 0)) DESC;
|
正常标准:死元组占比<10%,autovacuum正常清理
异常处理
1.常规回收空间:VACUUM ANALYZE 表名;
2.彻底回收空间返还操作系统(锁表,业务低峰执行):VACUUM FULL ANALYZE 表名;
1.2.14 索引膨胀完整查询
|
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间",
current_database() AS db, schemaname, tablename,bs, reltuples::bigint AS tups, relpages::bigint AS pages, otta,
ROUND(CASE WHEN otta=0 OR sml.relpages=0 OR sml.relpages=otta THEN 0.0 ELSE sml.relpages/otta::numeric END,1) AS tbloat,
CASE WHEN relpages < otta THEN 0 ELSE relpages::bigint - otta END AS wastedpages,
CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes,
CASE WHEN relpages < otta THEN $$0 bytes$$::text ELSE (bs*(relpages-otta))::bigint || $$ bytes$$ END AS wastedsize,
iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta,
ROUND(CASE WHEN iotta=0 OR ipages=0 OR ipages=iotta THEN 0.0 ELSE ipages/iotta::numeric END,1) AS ibloat,
CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END AS wastedipages,
CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes,
CASE WHEN ipages < iotta THEN $$0 bytes$$ ELSE (bs*(ipages-iotta))::bigint || $$ bytes$$ END AS wastedisize,
CASE WHEN relpages < otta THEN
CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta::bigint) END
ELSE CASE WHEN ipages < iotta THEN bs*(relpages-otta::bigint)
ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END
END AS totalwastedbytes
FROM (
SELECT
nn.nspname AS schemaname,
cc.relname AS tablename,
COALESCE(cc.reltuples,0) AS reltuples,
COALESCE(cc.relpages,0) AS relpages,
COALESCE(bs,0) AS bs,
COALESCE(CEIL((cc.reltuples*((datahdr+ma-
(CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta,
COALESCE(c2.relname,$$?$$) AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta
FROM
pg_class cc
JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname <> $$information_schema$$
LEFT JOIN
(
SELECT
ma,bs,foo.nspname,foo.relname,
(datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
(maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
FROM (
SELECT
ns.nspname, tbl.relname, hdr, ma, bs,
SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth,
MAX(coalesce(null_frac,0)) AS maxfracsum,
hdr+(
SELECT 1+count(*)/8
FROM pg_stats s2
WHERE null_frac<>0 AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname
) AS nullhdr
FROM pg_attribute att
JOIN pg_class tbl ON att.attrelid = tbl.oid
JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
LEFT JOIN pg_stats s ON s.schemaname=ns.nspname
AND s.tablename = tbl.relname
AND s.inherited=false
AND s.attname=att.attname,
(
SELECT
(SELECT current_setting($$block_size$$)::numeric) AS bs,
CASE WHEN SUBSTRING(SPLIT_PART(v, $$ $$, 2) FROM $$#"[0-9]+.[0-9]+#"%$$ for $$#$$)
IN ($$8.0$$,$$8.1$$,$$8.2$$) THEN 27 ELSE 23 END AS hdr,
CASE WHEN v ~ $$mingw32$$ OR v ~ $$64-bit$$ THEN 8 ELSE 4 END AS ma
FROM (SELECT version() AS v) AS foo
) AS constants
WHERE att.attnum > 0 AND tbl.relkind=$$r$$
GROUP BY 1,2,3,4,5
) AS foo
) AS rs
ON cc.relname = rs.relname AND nn.nspname = rs.nspname
LEFT JOIN pg_index i ON indrelid = cc.oid
LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
) AS sml
order by wastedbytes desc limit 20;
|
异常处理
无锁重建索引(业务低峰推荐):
|
REINDEX INDEX CONCURRENTLY 索引名;
REINDEX TABLE CONCURRENTLY 表名;
|
1.2.15 库/表/索引大小查询()
1.单库大小
|
SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size FROM pg_database;
|
2.单表总大小(含索引+toast)
|
select pg_size_pretty(pg_total_relation_size('public.表名'));
|
3.全表空间排序
|
SELECT
format('%I.%I', table_schema, table_name) AS table_name,
pg_size_pretty(pg_table_size((format('%I.%I', table_schema, table_name))::regclass)) AS table_size,
pg_size_pretty(pg_indexes_size((format('%I.%I', table_schema, table_name))::regclass)) AS indexes_size,
pg_size_pretty(pg_total_relation_size((format('%I.%I', table_schema, table_name))::regclass)) AS total_size
FROM information_schema.tables
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
AND table_type = 'BASE TABLE' -- 仅普通表
ORDER BY pg_total_relation_size((format('%I.%I', table_schema, table_name))::regclass) DESC;
|
1.2.16 Autovacuum自动清理监控
1. 正在执行的vacuum进度
|
SELECT p.pid,
p.datname,
p.query,
p.backend_type,
a.phase,
a.heap_blks_scanned / a.heap_blks_total::float * 100 AS "% scanned",
a.heap_blks_vacuumed / a.heap_blks_total::float * 100 AS "% vacuumed",
pg_size_pretty(pg_table_size(a.relid)) AS "table size",
pg_get_userbyid(c.relowner) AS owner
FROM pg_stat_activity p
JOIN pg_stat_progress_vacuum a ON a.pid = p.pid
JOIN pg_class c ON c.oid = a.relid
WHERE p.query LIKE 'autovacuum%';
|
2. 各表死元组、是否需要vacuum
|
SELECT *
,n_dead_tup > av_threshold AS av_needed
,CASE
WHEN reltuples > 0
THEN round(100.0 * n_dead_tup / (reltuples))
ELSE 0
END AS pct_dead
FROM (
SELECT N.nspname
,C.relname
,pg_stat_get_live_tuples(C.oid) AS n_live_tup
,pg_stat_get_dead_tuples(C.oid) AS n_dead_tup
,C.reltuples AS reltuples
,round(current_setting('autovacuum_vacuum_threshold')::INTEGER + current_setting('autovacuum_vacuum_scale_factor')::NUMERIC * C.reltuples) AS av_threshold
,date_trunc('minute', greatest(pg_stat_get_last_vacuum_time(C.oid), pg_stat_get_last_autovacuum_time(C.oid))) AS last_vacuum
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE C.relkind IN ('r','t')
AND N.nspname NOT IN ('pg_catalog','information_schema')
AND N.nspname !~ '^pg_toast'
) AS av
ORDER BY av_needed DESC ,n_dead_tup DESC;
|
1.2.17 锁阻塞链完整排查(定位阻塞源头)
|
select w1.pid as 等待进程,
w1.mode as 等待锁模式,
w2.usename as 等待用户,
w2.query as 等待会话SQL,
b1.pid as 持有锁进程,
b1.mode 持有锁模式,
b2.usename as 持有锁用户,
b2.query as 持有锁SQL,
b2.application_name 应用名称,
b2.client_addr 客户端IP
from pg_locks w1
join pg_stat_activity w2 on w1.pid=w2.pid
join pg_locks b1 on w1.transactionid=b1.transactionid and w1.pid!=b1.pid
join pg_stat_activity b2 on b1.pid=b2.pid
where not w1.granted;
|
1.2.18 用户账号、权限、过期时间巡检
|
SELECT
r.rolname AS username,
COALESCE(d.description, '无备注') AS comment,
r.rolvaliduntil AS password_expire_time,
r.rolsuper AS is_superuser,
r.rolcanlogin AS can_login,
r.rolreplication AS can_replicate,
r.rolconnlimit AS max_conn_limit
FROM pg_roles r
LEFT JOIN pg_shdescription d ON d.objoid = r.oid
WHERE r.rolcanlogin = true
ORDER BY r.rolname;
|
正常标准:无过期账号、超级用户数量受控、业务账号连接限制合理
异常处理:重置过期密码、回收多余super权限、限制账号最大连接
1.2.19 临时文件/大查询磁盘占用监控
|
SELECT * FROM pg_ls_tmpdir();
|
1.2.20 长事务xmin快照老化监控(防表膨胀核心)
|
SELECT
pid,
usename,
application_name,
client_addr,
backend_xmin,
age(backend_xmin) AS xmin_age,
now() - xact_start AS xact_duration,
state,
LEFT(query, 100) AS query_preview
FROM pg_stat_activity
WHERE backend_xmin IS NOT NULL
AND pid <> pg_backend_pid()
ORDER BY age(backend_xmin) DESC;
|
预防方案(库级别自动超时)
|
ALTER DATABASE test_db
SET idle_in_transaction_session_timeout = '3min';
ALTER DATABASE test_db
SET statement_timeout = '10min';
SELECT pg_reload_conf();
|
文档使用说明
1.日常巡检:按「1.1主机资源 → 1.2数据库实例」顺序逐条执行核对
2.故障排查:优先执行锁查询、长事务、慢SQL、表膨胀、IO负载
3.自动化适配:所有SQL可封装Shell脚本,定时输出巡检报告
4.生产规范:
- 禁止频繁执行VACUUM FULL,仅业务低峰使用