环境:
需求:
一条命令完成:
create_app.sh#!/bin/bash
# 用法: ./create_app.sh app_name app_password conn_limit
APP_NAME=$1
APP_PASS=$2
CONN_LIMIT=${3:-20}
if [ -z "$APP_NAME" ] || [ -z "$APP_PASS" ]; then
echo "Usage: $0 app_name app_password [conn_limit]"
exit 1
fi
APP_USER="${APP_NAME}_user"
APP_DB="${APP_NAME}_db"
sudo -iu postgres psql <<EOF
DO \$\$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='${APP_USER}') THEN
CREATE ROLE ${APP_USER}
LOGIN
PASSWORD '${APP_PASS}'
NOSUPERUSER
NOCREATEDB
NOCREATEROLE
NOREPLICATION;
END IF;
END
\$\$;
DO \$\$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname='${APP_DB}') THEN
CREATE DATABASE ${APP_DB}
OWNER ${APP_USER}
ENCODING 'UTF8'
TEMPLATE template0;
END IF;
END
\$\$;
EOF
sudo -iu postgres psql -d ${APP_DB} <<EOF
REVOKE ALL ON SCHEMA public FROM PUBLIC;
GRANT USAGE, CREATE ON SCHEMA public TO ${APP_USER};
ALTER DEFAULT PRIVILEGES
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO ${APP_USER};
ALTER DEFAULT PRIVILEGES
GRANT USAGE, SELECT ON SEQUENCES TO ${APP_USER};
ALTER ROLE ${APP_USER} CONNECTION LIMIT ${CONN_LIMIT};
ALTER ROLE ${APP_USER} SET statement_timeout = '30s';
EOF
echo "✔ Application ${APP_NAME} initialized successfully."
chmod +x create_app.sh
./create_app.sh order_service 'StrongPass123!' 20
pg_backup.sh#!/bin/bash
BACKUP_DIR="/data/pg_backup"
RETENTION_DAYS=7
DATE=$(date +%F)
mkdir -p ${BACKUP_DIR}
DB_LIST=$(sudo -iu postgres psql -Atc \
"SELECT datname FROM pg_database WHERE datistemplate = false;")
for DB in $DB_LIST; do
FILE="${BACKUP_DIR}/${DB}_${DATE}.dump"
echo "Backing up ${DB} ..."
sudo -iu postgres pg_dump -Fc ${DB} > ${FILE}
if [ $? -ne 0 ]; then
echo "Backup failed for ${DB}"
exit 1
fi
done
# 清理过期备份
find ${BACKUP_DIR} -type f -mtime +${RETENTION_DAYS} -delete
echo "✔ Backup completed at $(date)"
chmod +x pg_backup.sh
./pg_backup.sh
crontab -e
0 2 * * * /opt/pg/pg_backup.sh >> /var/log/pg_backup.log 2>&1
pg_stat_statements 解决的是 生产环境最核心的 3 个问题:
1️⃣ 哪些 SQL 真正在吃 CPU 2️⃣ 哪些 SQL 调用次数异常 3️⃣ 性能退化是“新 SQL”还是“老 SQL 变慢”
👉 没有它,所有性能问题都只能靠猜。
pg_stat_statements 是扩展,不是 PostgreSQL 默认自带表。永久开启的“正确姿势”(按顺序来)
这是唯一必须重启数据库的一步。
sudo -iu postgres psql postgres
ALTER SYSTEM SET shared_preload_libraries = 'pg_stat_statements';
重启:
systemctl restart postgresql-16
确认:
sudo -iu postgres psql -c "SHOW shared_preload_libraries;"
必须看到:
pg_stat_statements
这一步决定 开得稳不稳。
ALTER SYSTEM SET pg_stat_statements.max = 5000;
ALTER SYSTEM SET pg_stat_statements.track = 'top';
ALTER SYSTEM SET pg_stat_statements.track_utility = off;
ALTER SYSTEM SET pg_stat_statements.save = on;
解释(很关键):
| 参数 | 含义 | 为什么这样设 |
|---|---|---|
| max = 5000 | 统计 SQL 种类数 | 足够多,不浪费内存 |
| track = top | 只跟踪顶层 SQL | 避免函数内部噪音 |
| track_utility = off | 不统计 DDL | 降低干扰 |
| save = on | 重启不丢数据 | 真正“永久” |
SELECT pg_reload_conf();
建议在 postgres 库:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
验证:
SELECT * FROM pg_stat_statements LIMIT 1;
pg_health.sql-- 连接数
SELECT count(*) AS connections FROM pg_stat_activity;
-- 长事务
SELECT pid, now() - xact_start AS duration, query
FROM pg_stat_activity
WHERE state <> 'idle'
AND now() - xact_start > interval '5 minutes';
-- 慢 SQL TOP 10
SELECT query, calls, total_exec_time
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
-- 死锁
SELECT deadlocks FROM pg_stat_database;
-- autovacuum 停止表
SELECT relname, last_autovacuum
FROM pg_stat_user_tables
WHERE last_autovacuum IS NULL;
pg_health_check.sh#!/bin/bash
REPORT_DIR="/data/pg_health"
DATE=$(date +%F_%H%M)
mkdir -p ${REPORT_DIR}
sudo -iu postgres psql <<EOF > ${REPORT_DIR}/health_${DATE}.txt
\i /opt/pg/pg_health.sql
EOF
echo "✔ Health check done: ${REPORT_DIR}/health_${DATE}.txt"
0 * * * * /opt/pg/pg_health_check.sh
/opt/pg/
├── create_app.sh
├── pg_backup.sh
├── pg_health.sql
├── pg_health_check.sh
本文由 best 创作,采用 知识共享署名 3.0 中国大陆许可协议 进行许可。 可自由转载、引用,但需署名作者且注明文章出处。