赞
踩
前面介绍了 PostgreSQL 基于 pgpool 实现读写分离实践、数据库备份与恢复、主从数据目录同步工具 pg_rewind、数据库作业调度工具、性能优化、日志与日常巡检等相关的知识点,今天我将详细的为大家介绍 PostgreSQL 数据库运维管理相关知识,希望大家能够从中收获多多!如有帮助,请点在看、转发支持一波!!!
su - postgres
#将旧的数据库目录重命名
mkdir /usr/local/pgsql.old
chown -R postgres.postgres /usr/local/pgsql.old
mv /usr/local/pgsql/* /usr/local/pgsql.old/
exit #切回root
cd /opt
rz #上传源码包
tar -zxvf postgresql-11.16.tar.gz #解压
cd postgresql-11.16/ #进入到源码目录
./configure --prefix=/usr/local/pgsql --with-openssl --with-pgport=5432 --with-tcl --with-perl --with-python --with-libxml --with-libxslt --with-ossp-uuid --with-pam --with-ldap
gmake world #gmake包括第三方插件全部编译
gmake install-world #包括第三方插件全部安装
mkdir /usr/local/pgsql/data #创建数据目录
chown -R postgres.postgres /usr/local/pgsql
chown -R postgres.postgres /usr/local/pgsql/data #授权数据目录
su - postgres
#初始化数据库
/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data --encoding=UTF8 --lc-collate=en_US.UTF-8 --lc-ctype=en_US.UTF-8 #初始化数据库
#如果有外部extension插件则在这安装插件
#关闭旧数据库
/usr/local/pgsql.old/bin/pg_ctl -D /usr/local/pgsql.old/data/ stop -m fast
#环境变量临时赋值本地ip
export PGHOST=127.0.0.1
#升级前检查
/usr/local/pgsql/bin/pg_upgrade -d /usr/local/pgsql.old/data/ -D /usr/local/pgsql/data/ -b /usr/local/pgsql.old/bin/ -B /usr/local/pgsql/bin/ -c
#升级
/usr/local/pgsql/bin/pg_upgrade -d /usr/local/pgsql.old/data/ -D /usr/local/pgsql/data/ -b /usr/local/pgsql.old/bin/ -B /usr/local/pgsql/bin/
#收集表的统计信息
./analyze_new_cluster.sh
cd $PGDATA
rm -f pg_hba.conf #删除新的pg_hba.conf
rm -f postgresql.conf #删除新的postgresql.conf
#拷贝旧的pg_hba.conf和postgresql.conf到升级的库
cp /usr/local/pgsql.old/data/pg_hba.conf $PGDATA/
cp /usr/local/pgsql.old/data/postgresql.conf $PGDATA/
#启动数据库
pg_ctl -D $PGDATA start
这是个bug,版本升级后,pg_config改变了,会导致后面装外部extension时没有装到指定目录。
#旧版本
/database/postgres11.old/psql/bin/pg_config
BINDIR = /database/postgres11.old/psql/bin
DOCDIR = /database/postgres11.old/psql/share/doc
HTMLDIR = /database/postgres11.old/psql/share/doc
INCLUDEDIR = /database/postgres11.old/psql/include
PKGINCLUDEDIR = /database/postgres11.old/psql/include
INCLUDEDIR-SERVER = /database/postgres11.old/psql/include/server
LIBDIR = /database/postgres11.old/psql/lib
PKGLIBDIR = /database/postgres11.old/psql/lib
LOCALEDIR = /database/postgres11.old/psql/share/locale
MANDIR = /database/postgres11.old/psql/share/man
SHAREDIR = /database/postgres11.old/psql/share
SYSCONFDIR = /database/postgres11.old/psql/etc
PGXS = /database/postgres11.old/psql/lib/pgxs/src/makefiles/pgxs.mk
CONFIGURE = '--prefix=/database/postgres11/psql/' '--with-perl' '--with-python'
CC = gcc
CPPFLAGS = -D_GNU_SOURCE
CFLAGS = -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2
CFLAGS_SL = -fPIC
LDFLAGS = -Wl,--as-needed -Wl,-rpath,'/database/postgres11/psql/lib',--enable-new-dtags
LDFLAGS_EX =
LDFLAGS_SL =
LIBS = -lpgcommon -lpgport -lpthread -lz -lreadline -lrt -lcrypt -ldl -lm
VERSION = PostgreSQL 11.6
更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
#新版本
/database/postgres11/psql/bin/pg_config
BINDIR = /database/postgres11/psql/bin
DOCDIR = /database/postgres11/psql/share/doc/postgresql
HTMLDIR = /database/postgres11/psql/share/doc/postgresql
INCLUDEDIR = /database/postgres11/psql/include
PKGINCLUDEDIR = /database/postgres11/psql/include/postgresql
INCLUDEDIR-SERVER = /database/postgres11/psql/include/postgresql/server
LIBDIR = /database/postgres11/psql/lib
PKGLIBDIR = /database/postgres11/psql/lib/postgresql
LOCALEDIR = /database/postgres11/psql/share/locale
MANDIR = /database/postgres11/psql/share/man
SHAREDIR = /database/postgres11/psql/share/postgresql
SYSCONFDIR = /database/postgres11/psql/etc/postgresql
PGXS = /database/postgres11/psql/lib/postgresql/pgxs/src/makefiles/pgxs.mk
CONFIGURE = '--prefix='
CC = gcc
CPPFLAGS = -D_GNU_SOURCE
CFLAGS = -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2
CFLAGS_SL = -fPIC
LDFLAGS = -Wl,--as-needed -Wl,-rpath,'/lib',--enable-new-dtags
LDFLAGS_EX =
LDFLAGS_SL =
LIBS = -lpgcommon -lpgport -lpthread -lz -lreadline -lrt -lcrypt -ldl -lm
VERSION = PostgreSQL 11.16
详见:进阶数据库系列(二十):PostgreSQL 数据库备份与恢复
然后创建对应的role和schema和database并且grant。
[postgres@pg_master ~]$ psql -h 192.168.233.30 -p 5432 -U postgres -d pgtest -E
# -h 主机名 默认读取环境变量 PGHOST PGHOST默认为当前主机
# -p 端口号 默认读取环境变量 PGPORT PGPORT默认为5432
# -U 用户名 默认读取环境变量 PGUSER PGUSER默认为postgres
# -d 数据库名 默认读取环境变量 PGDATABASE PGDATABASE默认为postgres
# -W 强制输入密码 当有配值环境变量 PGPASSWORD 时,无需输入密码,加入该参数后,强制用户登录时输入密码
# -E 回显命令对应的sql语句
CREATE DATABASE name [ [WITH] [OWNER [=] user_name]
[TEMPLATE [=] template]
[ENCODING [=] encoding]
[LC_COLLATE [=] lc_collate]
[LC_CTYPE [=] lc_ctype]
[TABLESPACE [=] tablespace]
[CONNECTION LIMIT [=] connlimit ] ]
name:要创建的数据库的名称。
user_name:拥有新数据库的⽤户的名称,或者使⽤默认所有者(执⾏命令的⽤户)DEFAULT。
template:创建新数据库的模板的名称,或者DEFAULT使⽤默认模板的模板(template1)。
encoding:在新数据库中使⽤的字符集编码。指定字符串常量(例如’SQL_ASCII’),整数编码数字或
DEFAULT以使⽤默认编码。 有关更多信息,请参⻅字符集⽀持。
lc_collate:在新数据库中使⽤的排序规则(LC_COLLATE)。这会影响应⽤于字符串的排序顺序,例如在使⽤ORDER BY的查询中,以及在⽂本列的索引中使⽤的顺序。 默认设置是使⽤模板数据库的排序规则。有关其他限制,请参⻅“注释”部分。
lc_ctype:在新数据库中使⽤的字符分类(LC_CTYPE)。 这会影响字符的分类,例如下,上和数字。 默认值是使⽤模板数据库的字符分类。有关其他限制,请参⻅下⽂。
tablespace:将与新数据库关联的表空间的名称,或者为DEFAULT以使⽤模板数据库的表空间。该表空间将是⽤于在此数据库中创建的对象的默认表空间。
connlimit:可能的最⼤并发连接数。 默认值-1表示没有限制。
create database etl; --创建一个etl数据库,其他参数不用配置,直接用模板数据库的即可
drop database etl; --删除数据库
更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
--创建管理员组 admin
create role admin;
--创建开发人员用户组 developer
create role developer;
--创建数据装载用户组 dataload
create role dataload;
--创建外部接口用户组 interface
create role interface;
--创建管理员 pgadmin
create role pgadmin with superuser login password 'pgadminAa123456';
--创建开发用户
create role yuzhenchao with login password 'yzc+Aa123456' connection limit 10 valid until '2023-01-16 00:00:00';
--创建数据装载用户
create role copyload with login password 'copy+Aa123456' connection limit 60 valid until '2023-01-16 00:00:00';
--创建外部接口用户
create role finebi with login password 'finebi+Aa123456' connection limit 20 valid until '2023-01-16 00:00:00';
--将pgadmin加入到admin组
alter group admin add user pgadmin;
--将yuzhenchao加入到developer组
alter group developer add user yuzhenchao;
--将copyload加入到dataload组
alter group dataload add user copyload;
--将finebi加入到interface用户组
alter group interface add user finebi;
--创建pgadmin对应的模式名pgadmin
create schema pgadmin;
--创建yuzhenchao对应的模式名yuzhenchao
create schema yuzhenchao;
--创建copyload对应的模式名copyload
create schema copyload;
--一般外部接口都只有只读权限,所以不需要给他建单独的模式
--将pgadmin模式的所有权限授权给pgadmin
grant create,usage on schema pgadmin to pgadmin;
--将yuzhenchao模式的所有权限授权给yuzhenchao
grant create,usage on schema yuzhenchao to yuzhenchao;
--将copyload模式的所有权限授权给copyload
grant create,usage on schema copyload to copyload;
--将pgadmin模式的usage权限授权给public
grant usage on schema pgadmin to public;
--将yuzhenchao模式的usage权限授权给public
grant usage on schema yuzhenchao to public;
--将copyload模式的usage权限授权给public
grant usage on schema copyload to public;
--任何用户都拥有public模式的所有权限
--出于安全,回收任何用户在public的create权限
revoke create on schema public from public;
/*
* pg中函数默认公开execute权限
* 通过pg的基于schema和基于role的默认权限实现
*/
--在schema为pgadmin上创建的任何函数,除定义者外,其他人调用需要显式授权
alter default privileges for role pgadmin revoke execute on functions from public;
--由pgadmin用户创建的任何函数,除定义者外,其他人调用需要显式授权
alter default privileges in schema pgadmin revoke execute on functions from public;
--在schema为yuzhenchao上创建的任何函数,除定义者外,其他人调用需要显式授权
alter default privileges for role yuzhenchao revoke execute on functions from public;
--由yuzhenchao用户创建的任何函数,除定义者外,其他人调用需要显式授权
alter default privileges in schema yuzhenchao revoke execute on functions from public;
--在schema为copyload上创建的任何函数,除定义者外,其他人调用需要显式授权
alter default privileges for role copyload revoke execute on functions from public;
--由copyload用户创建的任何函数,除定义者外,其他人调用需要显式授权
alter default privileges in schema copyload revoke execute on functions from public;
/*
* pg与oracle不同,没有select any table的权限
* 但是pg有默认权限
* 通过pg的基于schema和基于role的默认权限实现
*/
--在schema为pgadmin上创建的任何表默认公开select权限
alter default privileges in schema pgadmin grant select on tables to public;
--由pgadmin用户创建的任何表默认公开select权限
alter default privileges for role pgadmin grant select on tables to public;
--在schema为yuzhenchao上创建的任何表默认公开select权限
alter default privileges in schema yuzhenchao grant select on tables to public;
--由yuzhenchao用户创建的任何表默认公开select权限
alter default privileges for role yuzhenchao grant select on tables to public;
--在schema为copyload上创建的任何表默认公开select权限
alter default privileges in schema copyload grant select on tables to public;
--由copyload用户创建的任何表默认公开select权限
alter default privileges for role copyload grant select on tables to public;
/*
* 为了方便各用户的管理
* 需要用定义者权限创建动态sql函数
* 最终由pgadmin用户集中管理
*/
--为pgadmin用户创建sp_exec函数
create or replace function pgadmin.sp_exec(vsql varchar)
returns void --返回空
language plpgsql
security definer --定义者权限
as $function$
begin
execute vsql;
end;
$function$
;
--将对应模式的对应模式的函数给对应的模式的拥有者
alter function pgadmin.sp_exec(varchar) owner to pgadmin;
--将对应模式的sp_exec函数授权给定义者和集中用户execute权限
grant execute on function pgadmin.sp_exec(varchar) to pgadmin;
--为yuzhenchao用户创建sp_exec函数
create or replace function yuzhenchao.sp_exec(vsql varchar)
returns void --返回空
language plpgsql
security definer --定义者权限
as $function$
begin
execute vsql;
end;
$function$
;
--将对应模式的对应模式的函数给对应的模式的拥有者
alter function yuzhenchao.sp_exec(varchar) owner to yuzhenchao;
--将对应模式的sp_exec函数授权给定义者和集中用户execute权限
grant execute on function yuzhenchao.sp_exec(varchar) to yuzhenchao,pgadmin;
--为copyload用户创建sp_exec函数
create or replace function copyload.sp_exec(vsql varchar)
returns void --返回空
language plpgsql
security definer --定义者权限
as $function$
begin
execute vsql;
end;
$function$
;
--将对应模式的对应模式的函数给对应的模式的拥有者
alter function copyload.sp_exec(varchar) owner to copyload;
--将对应模式的sp_exec函数授权给定义者和集中用户execute权限
grant execute on function copyload.sp_exec(varchar) to copyload,pgadmin;
更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
create or replace function pgadmin.sp_execsql(exec_sql character varying,exec_user character varying)
returns void
language plpgsql
security definer
as $function$
/* 作者 : v-yuzhenc
* 功能 : 集中处理程序,以某用户的权限执行某条sql语句
* exec_sql : 需要执行的sql语句
* exec_user : 需要以哪个用户的权限执行该sql语句
* */
declare
p_user varchar := exec_user;
o_search_path varchar;
begin
--记录原来的模式搜索路径
execute 'show search_path;' into o_search_path;
--临时切换模式搜索路径
execute 'SET search_path TO '||p_user||',public,oracle';
case p_user
when 'pgadmin' then perform pgadmin.sp_exec(exec_sql);
when 'yuzhenchao' then perform yuzhenchao.sp_exec(exec_sql);
when 'copyload' then perform copyload.sp_exec(exec_sql);
else raise exception '未配置该用户:%',p_user;
end case;
--恢复模式搜索路径
execute 'SET search_path TO '||o_search_path;
exception when others then
--恢复模式搜索路径
execute 'SET search_path TO '||o_search_path;
raise exception '%',sqlerrm;
end;
$function$
;
--将对应模式的对应模式的函数给对应的模式的拥有者
alter function pgadmin.sp_execsql(varchar,varchar) owner to pgadmin;
--将对应模式的sp_exec函数授权给定义者和集中用户execute权限
grant execute on function pgadmin.sp_execsql(varchar,varchar) to pgadmin;
su - postgres
#先备份全局对象
pg_dumpall -f backup.sql --globals-only
#再备份数据库
pg_dump hy_observe -Fc > hy_observe.dump
su - postgres
#先恢复全局对象
psql
\i backup.sql
--创建对应的数据库
create database hy_observe;
\q
#pg_restore进行恢复
pg_restore -d hy_observe hy_observe.dump -v
# 开启归档日志
vi $PGDATA/postgresql.conf
wal_level = replica # 或者更高级别
archive_mode = on
# backup_in_progress文件用来辅助wal日志备份,通过删除配合test指令控制wal日志备份
archive_command = 'test ! -f /usr/local/pgsql/backup_in_progress || (test ! -f /usr/local/pgsql/data/pg_archive/%f && cp %p /usr/local/pgsql/data/pg_archive/%f)'
# 重启数据库
pg_ctl restart -mf
touch /usr/local/pgsql/backup_in_progress
# 开始基础备份,可以在代码里连接数据库执行
psql -c "select pg_start_backup('hot_backup');"
# 将数据库文件进行备份
BACKUPDATE=`date '+%Y%m%d%H%m%S'`
tar -cf /data/pg_backup/pgbackup_${BACKUPDATE}.tar $PGDATA
# 结束备份,可以在代码里连接数据库执行
psql -c "select pg_stop_backup();"
# 停止wal日志备份
rm /usr/local/pgsql/backup_in_progress
# 将wal日志和基础备份打包在一起
tar -rf /data/pg_backup/pgbackup_${BACKUPDATE}.tar /usr/local/pgsql/data/pg_archive
pg_ctl stop -mf
mv $PGDATA ${PGDATA}.old
tar -xf /data/pg_backup/pgbackup_${BACKUPDATE}.tar -C $PGDATA
vi $PGDATA/recovery.conf
restore_command = 'cp /usr/local/pgsql/data/pg_archive/%f %p'
# 指定要恢复的时间点,也可以不指定,直接恢复所有数据
recovery_target_time = '2022-09-01 10:00:00'
pg_ctl start
更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
su - postgres
#进入到数据目录
cd $PGDATA
#创建证书
openssl req -new -x509 -days 365 -nodes -text -out server.crt -keyout server.key -subj "/CN=pg_master"
#只读权限
chmod 400 server.{crt,key}
#修改pg_hba.conf
vi $PGDATA/pg_hba.conf
#所有远程连接都通过ssl连接
hostssl all postgres 0.0.0.0/0 md5
hostssl all repl 192.168.233.0/24 trust
hostssl replication repl 192.168.233.0/24 md5
hostssl all all 0.0.0.0/0 md5
#开启ssl
alter system set ssl=on;
#重新加载数据库配置
select pg_reload_conf();
#重新登录
\q
psql
#查看当前连接信息
\conninfo
#查看所有连接信息
select
pg_ssl.pid
,pg_ssl.ssl
,pg_ssl.version
,pg_sa.backend_type
,pg_sa.usename
,pg_sa.client_addr
from pg_stat_ssl pg_ssl
inner join pg_stat_activity pg_sa
on (pg_ssl.pid = pg_sa.pid);
show password_encryption;--md5
select * from pg_shadow where usename='yuzhenchao';
alter role yuzhenchao valid until '2022-12-31 23:59:59';
select * from pg_user where usename='yuzhenchao';
注意:
pg密码有效期仅针对客户端有效,服务器端不受限制。
网络访问控制文件中不能配置为trust认证方式
ls -atl $LD_LIBRARY_PATH/passwordcheck*
alter system set shared_preload_libraries=pg_stat_statements,passwordcheck;
pg_ctl restart -mf
ls -atl $LD_LIBRARY_PATH/auth_delay*
--重启生效
alter system set shared_preload_libraries=pg_stat_statements,passwordcheck,auth_delay;
pg_ctl restart -mf
--重新加载生效
alter system set auth_delay.milliseconds=5000;
--重新加载
select pg_reload_conf();
pg_ctl reload
使用createuser命令加上-W选项创建用户
postgresql 服务器日志: ,更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
su - postgres
cd /opt
wget https://api.pgxn.org/dist/orafce/3.21.0/orafce-3.21.0.zip --no-check-certificate
unzip orafce-3.21.0.zip #解压
cd orafce-3.21.0/ #进入orafce-3.21.0目录
make clean
make #编译
make install #安装
psql -d pgtest -U pgadmin -W
create extension orafce; --创建orafce扩展
\q
cd /opt
wget https://github.com/Kitware/CMake/releases/download/v3.16.2/cmake-3.16.2.tar.gz
tar -zxvf cmake-3.16.2.tar.gz
cd cmake-3.16.2
./configure --prefix=/usr/local/cmake-3.16.2
make -j 4
make install
vi /etc/profile
export CMAKE_HOME=/usr/local/cmake-3.16.2
export PATH=$CMAKE_HOME/bin:$PATH
source /etc/profile
cd /opt
wget https://download.osgeo.org/geos/geos-3.11.0.tar.bz2 --no-check-certificate
tar -jxvf geos-3.11.0.tar.bz2
cd geos-3.11.0/
./configure --prefix=/usr/local/geos-3.11.0
make -j 4
make install
cd /opt
wget https://www.sqlite.org/2022/sqlite-autoconf-3390100.tar.gz --no-check-certificate
tar -zxvf sqlite-autoconf-3390100.tar.gz
cd sqlite-autoconf-3390100
vi ./sqlite3.c
#define SQLITE_CORE 1
#define SQLITE_AMALGAMATION 1
#ifndef SQLITE_PRIVATE
# define SQLITE_PRIVATE static
#endif
#define SQLITE_ENABLE_COLUMN_METADATA 1 //增加这句
./configure --prefix=/usr/local/sqlite
make -j 4
make install
mv /usr/bin/sqlite3 /usr/bin/sqlite3_old
ln -s /usr/local/sqlite/bin/sqlite3 /usr/bin/sqlite3
sqlite3 --version
export PKG_CONFIG_PATH=/usr/local/sqlite/lib/pkgconfig:$PKG_CONFIG_PATH
cd /opt
wget http://download.osgeo.org/proj/proj-6.3.2.tar.gz
tar -zxvf proj-6.3.2.tar.gz
cd proj-6.3.2/
./configure --prefix=/usr/local/proj-6.3.2
make -j 4
make install
cd /opt
wget https://download.osgeo.org/gdal/3.2.1/gdal-3.2.1.tar.gz --no-check-certificate
tar -zxvf gdal-3.2.1.tar.gz
cd gdal-3.2.1
./configure --prefix=/usr/local/gdal-3.2.1 --with-proj=/usr/local/proj-6.3.2
make -j 4
make install
cd /opt
wget https://github.com/json-c/json-c/archive/json-c-0.13.1-20180305.tar.gz
tar -zxvf json-c-0.13.1-20180305.tar.gz
cd json-c-json-c-0.13.1-20180305
./configure --prefix=/usr/local/json-c-0.13.1
make -j 4
make install
cd /opt
wget https://mirror.ossplanet.net/gnome/sources/libxml2/2.9/libxml2-2.9.14.tar.xz --no-check-certificate
tar -xvf libxml2-2.9.14.tar.xz
cd libxml2-2.9.14
chmod +x configure
./configure --prefix=/usr/local/libxml2-2.9.14
make -j 4
make install
cd /opt
wget https://github.com/protocolbuffers/protobuf/archive/v3.10.1.tar.gz
tar -zxvf v3.10.1.tar.gz
cd protobuf-3.10.1/
./autogen.sh #自动生成configure配置文件
./configure --prefix=/usr/local/protobuf-3.10.1
make -j 4
make install
vi /etc/profile
export PROTOBUF_HOME=/usr/local/protobuf-3.10.1
export PATH=$PROTOBUF_HOME/bin:$PATH
source /etc/profile
protoc --version
libprotoc 3.10.1
cd /opt
wget https://github.com/protobuf-c/protobuf-c/releases/download/v1.3.2/protobuf-c-1.3.2.tar.gz
tar -zxvf protobuf-c-1.3.2.tar.gz
cd protobuf-c-1.3.2/
#导入protobuf的pkgconfig,否则"--No package 'protobuf' found"
export PKG_CONFIG_PATH=/usr/local/protobuf-3.10.1/lib/pkgconfig
./configure --prefix=/usr/local/protobuf-c-1.3.2
make -j 4
make install
vi /etc/profile
export PROTOBUFC_HOME=/usr/local/protobuf-c-1.3.2
export PATH=$PROTOBUFC_HOME/bin:$PATH
source /etc/profile
yum -y install boost-devel
cd /opt
wget https://github.com/CGAL/cgal/archive/releases/CGAL-4.13.tar.gz
tar -zxvf CGAL-4.13.tar.gz
cd cgal-releases-CGAL-4.13/
mkdir build && cd build
cmake ..
make
make install
cd /opt
wget https://github.com/Oslandia/SFCGAL/archive/v1.3.7.tar.gz
tar -zxvf v1.3.7.tar.gz
cd SFCGAL-1.3.7
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/sfcgal-1.3.7 ..
make -j 4
make install
vi /etc/ld.so.conf
include ld.so.conf.d/*.conf
/usr/local/pgsql/lib
/usr/local/proj-6.3.2/lib
/usr/local/gdal-3.2.1/lib
/usr/local/geos-3.11.0/lib64
/usr/local/sfcgal-1.3.7/lib64
/usr/local/json-c-0.13.1/lib
/usr/local/libxml2-2.9.14/lib
/usr/local/protobuf-3.10.1/lib
/usr/local/protobuf-c-1.3.2/lib
ldconfig -v #重启生效
su - postgres
cd /usr/local/pgsql/contrib
wget http://download.osgeo.org/postgis/source/postgis-3.2.1.tar.gz
tar -zxvf postgis-3.2.1.tar.gz
cd postgis-3.2.1/
./configure --prefix=/usr/local/pgsql --with-gdalconfig=/usr/local/gdal-3.2.1/bin/gdal-config --with-pgconfig=/usr/local/pgsql/bin/pg_config --with-geosconfig=/usr/local/geos-3.11.0/bin/geos-config --with-projdir=/usr/local/proj-6.3.2 --with-xml2config=/usr/local/libxml2-2.9.14/bin/xml2-config --with-jsondir=/usr/local/json-c-0.13.1 --with-protobufdir=/usr/local/protobuf-c-1.3.2 --with-sfcgal=/usr/local/sfcgal-1.3.7/bin/sfcgal-config
make -j 4
make install
psql -d pgtest -U pgadmin -W
--postgis扩展
create extension postgis;
--验证栅格类数据需要的raster扩展
create extension postgis_raster;
--如果安装带有sfcgal,验证下三维sfcgal扩展
create extension postgis_sfcgal;
create extension fuzzystrmatch;
create extension postgis_tiger_geocoder;
create extension postgis_topology;
\q
创建extension时遇到问题
could not load library "/usr/local/pgsql/lib/postgis-3.so": /usr/local/pgsql/lib/postgis-3.so: undefined symbol: GEOSLargestEmpt
查找原因,是geos存在多个版本
ldconfig -p | grep libgeos_c.so.1
libgeos_c.so.1 (libc6,x86-64) => /usr/geos39/lib64/libgeos_c.so.1
libgeos_c.so.1 (libc6,x86-64) => /usr/local/geos-3.11.0/lib64/libgeos_c.so.1
#查找geos39
rpm -qa geos39
geos39-3.9.2-1.rhel7.x86_64
解决方案:卸载geos39-3.9.2-1.rhel7.x86_64
再次校验,发现只剩一个了
ldconfig -p | grep libgeos_c.so.1
libgeos_c.so.1 (libc6,x86-64) => /usr/local/geos-3.11.0/lib64/libgeos_c.so.1
最后 create extension postgis; 成功了
更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
标识符总长度不超过63,由于oracle标识符长度不超过30,原则上,为了兼容oracle,标识符长度最好不要超过30;
对象名(表名、列名、函数名、视图名、序列名、等对象名称)规范,对象名务必只使用小写字母,下划线,数字。不要以pg开头,不要以数字开头,不要使用保留字;
查询中的别名不要使用 “小写字母,下划线,数字” 以外的字符,例如中文;
主键索引应以 pk_ 开头, 唯一索引要以 uk_ 开头,普通索引要以 idx_ 打头
临时表以 tmp_ 开头,子表以规则结尾,例如按年分区的主表如果为tbl, 则子表为tbl_2016,tbl_2017等;
库名最好以部门名字开头 + 功能,如 xxx_yyy,xxx_zzz,便于辨识;
禁用public schema,应该为每个应用分配对应的schema,schema_name最好与user name一致。
多表中的相同列,必须保证列名一致,数据类型一致;
btree索引字段不建议超过2000字节,如果有超过2000字节的字段需要建索引,建议使用函数索引(例如哈希值索引),或者使用分词索引;
对于频繁更新的表,建议建表时指定表的fillfactor=85,每页预留15%的空间给HOT更新使用;(create table test123(id int, info text) with(fillfactor=85); CREATE TABLE)
表结构中字段定义的数据类型与应用程序中的定义保持一致,表之间字段校对规则一致,避免报错或无法使用索引的情况发生;
建议有定期历史数据删除需求的业务,表按时间分区,删除时不要使用DELETE操作,而是DROP或者TRUNCATE对应的表;
为了全球化的需求,所有的字符存储与表示,均以UTF-8编码;
对于值与堆表的存储顺序线性相关的数据,如果通常的查询为范围查询,建议使用BRIN索引。例如流式数据,时间字段或自增字段,可以使用BRIN索引,减少索引的大小,加快数据插入速度。(create index idx on tbl using brin(id); )
设计时应尽可能选择合适的数据类型,能用数字的坚决不用字符串,使用好的数据类型,可以使用数据库的索引,操作符,函数,提高数据的查询效率;
应该尽量避免全表扫描(除了大数据量扫描的数据分析),PostgreSQL支持几乎所有数据类型的索引;
应该尽量避免使用数据库触发器,这会使得数据处理逻辑复杂,不便于调试;
未使用的大对象,一定要同时删除数据部分,否则大对象数据会一直存在数据库中,与内存泄露类似;
对于固定条件的查询,可以使用部分索引,减少索引的大小,同时提升查询效率;(create index idx on tbl (col) where id=1;)
对于经常使用表达式作为查询条件的语句,可以使用表达式或函数索引加速查询;(create index idx on tbl ( exp ); )
如果需要调试较为复杂的逻辑时,不建议写成函数进行调试,可以使用plpgsql的匿名代码块;
当用户有prefix或者 suffix的模糊查询需求时,可以使用索引,或反转索引达到提速的需求;(select * from tbl where reverse(col) ~ ‘^def’; – 后缀查询使用反转函数索引)
用户应该对频繁访问的大表(通常指超过8GB的表,或者超过1000万记录的表)进行分区,从而提升查询的效率、更新的效率、备份与恢复的效率、建索引的效率等等;
设计表结构时必须加上字段数据的入库时间inputed_time和数据的更新时间updated_time;
统计行数用count(*)或者count(1),count(列名)不会统计列为空的行;
count(distinct col) 计算该列的非NULL不重复数量,NULL不被计数;
count(distinct (col1,col2,…) ) 计算多列的唯一值时,NULL会被计数,同时NULL与NULL会被认为是想同的;
NULL是UNKNOWN的意思,也就是不知道是什么。 因此NULL与任意值的逻辑判断都返回NULL;
除非是ETL程序,否则应该尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理;
尽量不要使用 select * from t ,用具体的字段列表代替*,不要返回用不到的任何字段,另外表结构发生变化也容易出现问题。
数据订正时,删除和修改记录时,要先select,避免出现误删除,确认无误才能提交执行;
用户可以使用explain analyze查看实际的执行计划,但是如果需要查看的执行计划设计数据的变更,必须在事务中执行explain analyze,然后回滚;
如何并行创建索引,不堵塞表的DML,创建索引时加CONCURRENTLY关键字,就可以并行创建,不会堵塞DML操作,否则会堵塞DML操作;(create index CONCURRENTLY idx on tbl(id); )
为数据库访问账号设置复杂密码;
业务系统,开发测试账号,不要使用数据库超级用户,非常危险;
应该为每个业务分配不同的数据库账号,禁止多个业务共用一个数据库账号;
大批量数据入库的优化,如果有大批量的数据入库,建议使用copy语法,或者 insert into table values (),(),…(); 的方式,提高写入速度。
游标使用后要及时关闭;
两阶段提交的事务,要及时提交或回滚,否则可能导致数据库膨胀;
不要使用delete 全表,性能很差,请使用truncate代替;
应用程序一定要开启autocommit,同时避免应用程序自动begin事务,并且不进行任何操作的情况发生,某些框架可能会有这样的问题;
在函数中,或程序中,不要使用count(*)判断是否有数据,很慢。 建议的方法是limit 1;
必须选择合适的事务隔离级别,不要使用越级的隔离级别,例如READ COMMITTED可以满足时,就不要使用repeatable read和serializable隔离级别;
高峰期对大表添加包含默认值的字段,会导致表的rewrite,建议只添加不包含默认值的字段,业务逻辑层面后期处理默认值;
可以预估SQL执行时间的操作,建议设置语句级别的超时,可以防止雪崩,也可以防止长时间持锁;
PostgreSQL支持DDL事务,支持回滚DDL,建议将DDL封装在事务中执行,必要时可以回滚,但是需要注意事务的长度,避免长时间堵塞DDL对象的读操作;
如果用户需要在插入数据和,删除数据前,或者修改数据后马上拿到插入或被删除或修改后的数据,建议使用insert into … returning …; delete … returning …或update … returning …; 语法。减少数据库交互次数;
自增字段建议使用序列,序列分为2字节,4字节,8字节几种(serial2,serial4,serial8)。按实际情况选择。 禁止使用触发器产生序列值;
使用窗口查询减少数据库和应用的交互次数;
如何判断两个值是不是不一样(并且将NULL视为一样的值),使用col1 IS DISTINCT FROM col2;
对于经常变更,或者新增,删除记录的表,应该尽量加快这种表的统计信息采样频率,获得较实时的采样,输出较好的执行计划。
PostgreSQL优化一方面是找出系统的瓶颈,提高PostgreSQL数据库整体的性能;
另一方面,需要合理的结构设计和参数调整,以提高用户操作响应的速度;
同时还要尽可能的节省系统资源,以便系统可以提供更大负荷的服务。
PostgreSQL数据库优化是多方面的,原则是减少系统的瓶颈,减少资源的占用,增加系统的反应速度。例如:
通过优化文件系统,提高磁盘IO的读写速度;
通过优化操作系统调度策略,提高PostgreSQL的在高负荷情况下负载能力;
优化表结构、索引、查询语句等使查询响应更快。
首先了解系统情况后便可做相关合理的调整,以达到性能优化的目的。
/*CPU查看CPU型号*/
cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c
/*查看物理CPU个数*/
cat /proc/cpuinfo | grep "physical id" | sort -u | wc -l
/*查看逻辑CPU个数*/
cat /proc/cpuinfo | grep "processor" | wc -l
/*查看CPU内核数*/
cat /proc/cpuinfo | grep "cpu cores" | uniq
/*查看单个物理CPU封装的逻辑CPU数量*/
cat /proc/cpuinfo | grep "siblings" | uniq
/*计算是否开启超线程
##逻辑CPU > 物理CPU x CPU核数 #开启超线程
##逻辑CPU = 物理CPU x CPU核数 #没有开启超线程或不支持超线程*/
/*查看是否超线程,如果cpu cores数量和siblings数量一致,则没有启用超线程,否则超线程被启用。*/
cat /proc/cpuinfo | grep -e "cpu cores" -e "siblings" | sort | uniq
/*内存
TOP
/*命令经常用来监控linux的系统状况,比如cpu、内存的使用等。*/
/*查看某个用户内存使用情况,如:postgres*/
top -u postgres
/*
内容解释:
PID:#进程的ID
USER:#进程所有者
PR:#进程的优先级别,越小越优先被执行
NInice:#值
VIRT:#进程占用的虚拟内存
RES:#进程占用的物理内存
SHR:#进程使用的共享内存
S:#进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数
%CPU:#进程占用CPU的使用率
%MEM:#进程使用的物理内存和总内存的百分比
TIME+:#该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。
COMMAND:#进程启动命令名称
常用的命令:
P:#按%CPU使用率排行
T:#按MITE+排行
M:#按%MEM排行
/*查看进程相关信息占用的内存情况,(进程号可以通过ps查看)如下所示:*/
pmap -d 14596
ps -e -o 'pid,comm,args,pcpu,rsz,vsz,stime,user,uid'
ps -e -o 'pid,comm,args,pcpu,rsz,vsz,stime,user,uid' | grep postgres | sort -nrk5
/*其中rsz为实际内存,上例实现按内存排序,由大到小*/
/*看内存占用*/
free -m
/*看硬盘占用率*/
df -h
/*查看IO情况*/
iostat -x 1 10
/*如果 iostat 没有,要 yum install sysstat安装这个包,第一眼看下图红色圈圈的那个如果%util接近100%,表明I/O请求太多,I/O系统已经满负荷,磁盘可能存在瓶颈,一般%util大于70%,I/O压力就比较大,读取速度有较多的wait,然后再看其他的参数,
内容解释:
rrqm/s:#每秒进行merge的读操作数目。即delta(rmerge)/s
wrqm/s:#每秒进行merge的写操作数目。即delta(wmerge)/s
r/s:#每秒完成的读I/O设备次数。即delta(rio)/s
w/s:#每秒完成的写I/0设备次数。即delta(wio)/s
rsec/s:#每秒读扇区数。即delta(rsect)/s
wsec/s:#每秒写扇区数。即delta(wsect)/s
rKB/s:#每秒读K字节数。是rsec/s的一半,因为每扇区大小为512字节
wKB/s:#每秒写K字节数。是wsec/s的一半
avgrq-sz:#平均每次设备I/O操作的数据大小(扇区)。即delta(rsect+wsect)/delta(rio+wio)
avgqu-sz:#平均I/O队列长度。即delta(aveq)/s/1000(因为aveq的单位为毫秒)
await:#平均每次设备I/O操作的等待时间(毫秒)。即delta(ruse+wuse)/delta(rio+wio)
svctm:#平均每次设备I/O操作的服务时间(毫秒)。即delta(use)/delta(rio+wio)
%util:#一秒中有百分之多少的时间用于I/O操作,或者说一秒中有多少时间I/O队列是非空的
/*找到对应进程*/
ll /proc/进程号/exe
更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
使用EXPLAIN语句来分析一个查询语句,执行如下语句:
EXPLAIN ANALYZE SELECT * FROM fruits;
下面是查询语句中不使用索引和使用索引的对比。首先,分析未使用索引时的查询情况,EXPLAIN语句执行如下:
EXPLAIN SELECT * FROM fruits WHERE f_name='apple';
然后,在fruits表的f_name字段上加上索引。执行添加索引的语句及结果如下:
CREATE INDEX index_name ON fruits(f_name);
现在,再分析上面的查询语句。执行的EXPLAIN语句及结果如下:
EXPLAIN ANALYZE SELECT * FROM fruits WHERE f_name='apple';
子查询可以一次性完成很多逻辑上需要多个步骤才能完成的SQL操作。子查询虽然可以使查询语句很灵活,但执行效率不高。执行子查询时,PostgreSQL需要为内层查询语句的查询结果建立一个临时表。然后外层查询语句从临时表中查询记 录。查询完毕后,再撤销这些临时表。因此,子查询的速度会受到一定的影响。如果查询的数据量比较大,这种影响就会随之增大。
在PostgreSQL中可以使用连接(JOIN)查询来替代子查询。连接查询不需要建立临时表,其速度比子查询要快,如果查询中使用到索引的话,性能会更好。连接之所以更有效率,是因为PostgreSQL不需要在内存中创建临时表来完成查询工作。
将字段很多的表分解成多个表
增加中间表
增加冗余字段
设计数据库表时尽量遵循范式理论的规约,尽可能少的冗余字段,让数据库设计看起来精致、优雅。但是,合理的加入冗余字段可以提高查询速度。
优化插入记录的速度
删除索引
使用批量插入
删除外键约束
禁止自动提交
使用COPY批量导入
PostgreSQL中提供了ANALYZE语句收集表内容的统计信息,然后把结果保存在系统表pg_statistic 里。
使用ANALYZ来分析fruits表,执行的语句:
ANALYZE VERBOSE fruits;
更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
配置较大的内存。足够大的内存,是提高PostgreSQL数据库性能的方法之一。内存的速度比磁盘I/0快得多,可以通过增加系统的缓冲区容量,使数据在内存中停留的时间更 长,以减少磁盘I/0。
配置高速磁盘系统,以减少读盘的等待时间,提高响应速度。
合理分布磁盘I/O,把磁盘I/O分散在多个设备上,以减少资源竞争,提高并行操作能力。
配置多处理器,PostgreSQL是多线程的数据库,多处理器可同时执行多个线程。
PostgreSQL既使用自身的缓冲区,也使用内核缓冲IO。这意味着数据会在内存中存储两次,首先是存入PostgreSQL缓冲区,然后是内核缓冲区。这被称为双重缓冲区处理。对大多数操作系统来说,这个参数是最有效的用于调优的参数。此参数的作用是设置PostgreSQL中用于缓存的专用内存量。
shared_buffers的默认值设置得非常低,因为某些机器和操作系统不支持使用更高的值。但在大多数现代设备中,通常需要增大此参数的值才能获得最佳性能。
建议的设置值为机器总内存大小的25%,但是也可以根据实际情况尝试设置更低和更高的值。实际值取决于机器的具体配置和工作的数据量大小。举个例子,如果工作数据集可以很容易地放入内存中,那么可以增加shared_buffers的值来包含整个数据库,以便整个工作数据集可以保留在缓存中。
在生产环境中,将shared_buffers设置为较大的值通常可以提供非常好的性能,但应当时刻注意找到平衡点。
postgres=# show shared_buffers;
shared_buffers
----------------
128MB
(1 row)
PostgreSQL将其WAL(预写日志)记录写入缓冲区,然后将这些缓冲区刷新到磁盘。由wal_buffers定义的缓冲区的默认大小为16MB,但如果有大量并发连接的话,则设置为一个较高的值可以提供更好的性能。
postgres=# show wal_buffers;
wal_buffers
-------------
4MB
(1 row)
effective_cache_size提供可用于磁盘高速缓存的内存量的估计值。它只是一个建议值,而不是确切分配的内存或缓存大小。它不会实际分配内存,而是会告知优化器内核中可用的缓存量。在一个索引的代价估计中,更高的数值会使得索引扫描更可能被使用,更低的数值会使得顺序扫描更可能被使用。在设置这个参数时,还应该考虑PostgreSQL的共享缓冲区以及将被用于PostgreSQL数据文件的内核磁盘缓冲区。默认值是4GB。
postgres=# show effective_cache_size;
effective_cache_size
----------------------
4GB
(1 row)
此配置用于复合排序。内存中的排序比溢出到磁盘的排序快得多,设置非常高的值可能会导致部署环境出现内存瓶颈,因为此参数是按用户排序操作。如果有多个用户尝试执行排序操作,则系统将为所有用户分配大小为work_mem *
总排序操作数的空间。全局设置此参数可能会导致内存使用率过高,因此强烈建议在会话级别修改此参数值。默认值为4MB。
postgres=# show work_mem;
work_mem
----------
4MB
(1 row)
maintenance_work_mem
是用于维护任务的内存设置。默认值为64MB。设置较大的值对于VACUUM,RESTORE,CREATE INDEX,ADD FOREIGN KEY和ALTER TABLE等操作的性能提升效果显著。
postgres=# show maintenance_work_mem;
maintenance_work_mem
----------------------
64MB
(1 row)
此参数的作用为在向客户端返回成功状态之前,强制提交等待WAL被写入磁盘。这是性能和可靠性之间的权衡。如果应用程序被设计为性能比可靠性更重要,那么关闭synchronous_commit
。这意味着成功状态与保证写入磁盘之间会存在时间差。在服务器崩溃的情况下,即使客户端在提交时收到成功消息,数据也可能丢失。
postgres=# show synchronous_commit;
synchronous_commit
--------------------
on
(1 row)
PostgreSQL将更改写入WAL。检查点进程将数据刷新到数据文件中。发生CHECKPOINT时完成此操作。这是一项开销很大的操作,整个过程涉及大量的磁盘读/写操作。用户可以在需要时随时发出CHECKPOINT指令,或者通过PostgreSQL的参数checkpoint_timeout
和checkpoint_completion_target
来自动完成。
checkpoint_timeout
参数用于设置WAL检查点之间的时间。将此设置得太低会减少崩溃恢复时间,因为更多数据会写入磁盘,但由于每个检查点都会占用系统资源,因此也会损害性能。此参数只能在postgresql.conf文件中或在服务器命令行上设置。
checkpoint_completion_target
指定检查点完成的目标,作为检查点之间总时间的一部分。默认值是 0.5。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。高频率的检查点可能会影响性能。
postgres=# show checkpoint_timeout;
checkpoint_timeout
--------------------
5min
(1 row)
postgres=# show checkpoint_completion_target;
checkpoint_completion_target
------------------------------
0.5
(1 row)
允许客户端连接的最大数目
强制把数据同步更新到磁盘,如果系统的IO压力很大,把改参数改为off
在fsync打开的情况下,优化后性能能够提升30%左右。因为有部分优化选项在默认的SQL测试语句中没有体现出它的优势,如果到实际测试中,提升应该不止30%。
测试的过程中,主要的瓶颈就在系统的IO,如果需要减少IO的负荷,最直接的方法就是把fsync关闭,但是这样就会在掉电的情况下,可能会丢失部分数据。
事务提交后,日志写到wal log上到wal_buffer写入到磁盘的时间间隔。需要配合commit_sibling
。能够一次写入多个事务,减少IO,提高性能
设置触发commit_delay的并发事务数,根据并发事务多少来配置。减少IO,提高性能
注意:并非所有参数都适用于所有应用程序类型。某些应用程序通过调整参数可以提高性能,有些则不会。必须针对应用程序及操作系统的特定需求来调整数据库参数。
下面介绍几个我认为重要的:
增加这个参数可以提升CREATE INDEX
和ALTER TABLE ADD FOREIGN KEY
的执行效率。
增加这个参数可以提升大量数据导入时候的速度。
这个参数设置为无效的时候,能够提升以下的操作的速度
CREATE TABLE AS SELECT
CREATE INDEX
ALTER TABLE SET TABLESPACE
CLUSTER等。
autovacuum
:默认为on,表示是否开起autovacuum。默认开起。特别的,当需要冻结xid时,尽管此值为off,PG也会进行vacuum。
autovacuum_naptime
:下一次vacuum的时间,默认1min。这个naptime会被vacuum launcher分配到每个DB上。autovacuum_naptime/num of db
。
log_autovacuum_min_duration
:记录autovacuum动作到日志文件,当vacuum动作超过此值时。“-1”表示不记录。“0”表示每次都记录。
autovacuum_max_workers
:最大同时运行的worker数量,不包含launcher本身。
autovacuum_work_mem
:每个worker可使用的最大内存数。
autovacuum_vacuum_threshold
:默认50。与autovacuum_vacuum_scale_factor
配合使用,autovacuum_vacuum_scale_factor
默认值为20%。当update,delete的tuples数量超过autovacuum_vacuum_scale_factor*table_size+autovacuum_vacuum_threshold
时,进行vacuum。如果要使vacuum工作勤奋点,则将此值改小。
autovacuum_analyze_threshold
:默认50。与autovacuum_analyze_scale_factor
配合使用。
autovacuum_analyze_scale_factor
:默认10%。当update,insert,delete的tuples数量超过autovacuum_analyze_scale_factor*table_size+autovacuum_analyze_threshold
时,进行analyze。
autovacuum_freeze_max_age:200 million
。离下一次进行xid冻结的最大事务数。
autovacuum_multixact_freeze_max_age
:400 million。离下一次进行xid冻结的最大事务数。
autovacuum_vacuum_cost_delay
:如果为-1,取vacuum_cost_delay
值。
autovacuum_vacuum_cost_limit
:如果为-1,到vacuum_cost_limit
的值,这个值是所有worker的累加值。
在配置文件C:\PostgreSQL\data\pg96\postgresql.conf
中直接修改,修改前记得备份一下原文件,因为你不知道意外和明天不知道哪个会先来。修改完成之后,记得重启数据库哦。
ALTER SYSTEM SET configuration_parameter { TO | = } { value | 'value' | DEFAULT }
例如:我们现在要修改 maintenance_work_mem
。
--查看所有数据库参数的值
show all;
show maintenance_work_mem;
--注意这里的设置不会改变postgresql.conf,只会改变postgresql.conf
ALTER SYSTEM SET maintenance_work_mem= 1048576;
--重启数据库
show maintenance_work_mem;
--取消postgresql.auto.conf的参数设置
ALTER SYSTEM SET maintenance_work_mem= default;
max_connections = 300 #(change requires restart)
unix_socket_directories = '.' #comma-separated list of directories
shared_buffers = 194GB #尽量用数据库管理内存,减少双重缓存,提高使用效率
huge_pages = on #on, off, or try,使用大页
work_mem = 256MB # min 64kB ,减少外部文件排序的可能,提高效率
maintenance_work_mem = 2GB #min 1MB,加速建立索引
autovacuum_work_mem = 2GB #min 1MB, or -1 to use maintenance_work_mem ,加速垃圾回收。
dynamic_shared_memory_type = mmap #the default is the first option
vacuum_cost_delay = 0 #0-100 milliseconds,垃圾回收不妥协,极限压力下,减少膨胀可能性。
bgwriter_delay = 10ms #10-10000ms between rounds,刷shared buffer脏页的进程调度间隔,尽量高频调度,减少用户进程申请不到内存而需要主动刷脏页的可能(导致RT升高)。
bgwriter_lru_maxpages = 1000 #0-1000 max buffers written/round , 一次最多刷多少脏页。
bgwriter_lru_multiplier = 10.0 #0-10.0 multipler on buffers scanned/round 一次扫描多少个块,上次刷出脏页数量的倍数。
effective_io_concurrency = 2 #1-1000; 0 disables prefetching , 执行节点为bitmap heap scan时,预读的块数。
wal_level = minimal #minimal, archive, hot_standby, or logical , 如果现实环境,建议开启归档。
synchronous_commit = off #synchronization level; ,异步提交。
wal_sync_method = open_sync # the default is the first option ,因为没有standby,所以写xlog选择一个支持O_DIRECT的fsync方法。
full_page_writes = off # recover from partial page writes ,生产中,如果有增量备份和归档,可以关闭,提高性能。
wal_buffers = 1GB # min 32kB, -1 sets based on shared_buffers ,wal buffer大小,如果大量写wal buffer等待,则可以加大。
wal_writer_delay = 10ms #1-10000 milliseconds wal buffer调度间隔,和bg writer delay类似。
commit_delay = 20 #range 0-100000, in microseconds ,分组提交的等待时间。
commit_siblings = 9 #range 1-1000 , 有多少个事务同时进入提交阶段时,就触发分组提交。
checkpoint_timeout = 55min #range 30s-1h 时间控制的检查点间隔。
max_wal_size = 320GB #2个检查点之间最多允许产生多少个XLOG文件。
checkpoint_completion_target = 0.99 #checkpoint target duration, 0.0 - 1.0 ,平滑调度间隔,假设上一个检查点到现在这个检查点之间产生了100个XLOG,则这次检查点需要在产生100*checkpoint_completion_target个XLOG文件的过程中完成。PG会根据这些值来调度平滑检查点。
random_page_cost = 1.0 #same scale as above , 离散扫描的成本因子,本例使用的SSD IO能力足够好。
effective_cache_size = 240GB #可用的OS CACHE
log_destination = 'csvlog' #Valid values are combinations of
logging_collector = on #Enable capturing of stderr and csvlog
log_truncate_on_rotation = on #If on, an existing log file with the
update_process_title = off
track_activities = off
autovacuum = on #Enable autovacuum subprocess? 'on'
autovacuum_max_workers = 4 #max number of autovacuum subprocesses ,允许同时有多少个垃圾回收工作进程。
autovacuum_naptime = 6s #time between autovacuum runs,自动垃圾回收探测进程的唤醒间隔。
autovacuum_vacuum_cost_delay = 0 #default vacuum cost delay for,垃圾回收不妥协。
编辑 $PGDATA/postgresql.conf
文件
vi $PGDATA/postgresql.conf
# 做以下修改,下面2部分未提及的全部备注掉
# - Where to Log -
log_destination = 'csvlog' # 日志输出格式
logging_collector = on # 日志收集器,打开后某些不会出现在审计日志中的日志会被重定向到审计日志
log_directory = 'pg_log' # 相对于 $PGDATA 的相对路径,全路径即为 $PGDATA/pg_log
# 保留近7天的审计日志,轮询替换
log_filename = 'postgresql.%a' #日志名称
log_file_mode = 0600 # 只有postgres有读写权限
log_truncate_on_rotation = on # 覆盖同名日志
log_rotation_size = 0 # 不限制日志大小
log_min_messages = warning # 控制哪些消息级别被写入到审计日志
log_min_error_statement = error # 控制哪些导致一个错误情况的 SQL 语句被记录在服务器日志中
log_min_duration_statement = 0 # 记录所有sql运行时长,可以查慢sql
# - What to Log -
log_duration = on # 导致每一个完成的语句的持续时间被记录
log_lock_waits = on # 等锁超时记录日志,超时时间参数 deadlock_timeout
log_statement = 'mod' # mod记录所有ddl语句,外加数据修改语句例如INSERT, UPDATE、DELETE、TRUNCATE, 和COPY FROM
log_replication_commands = off # 不记录流复制命令
log_timezone = 'Asia/Shanghai' # 时区,查看操作系统时区 timedatectl | grep "Time zone"
重启数据库
pg_ctl restart -mf
更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
安装 file_fdw
插件
create extension file_fdw;
创建外部表
drop foreign table if exists pg_log_mon;
create foreign table pg_log_mon(
log_time timestamp
,user_name text
,database_name text
,process_id integer
,connection_from text
,session_id text
,session_line_num bigint
,command_tag text
,session_start_time timestamp
,virtual_transaction_id text
,transaction_id bigint
,error_severity text
,sql_state_code text
,message text
,detail text
,hint text
,internal_query text
,internal_query_pos integer
,context text
,query text
,query_pos integer
,location text
,application_name text
) server pg_file_server options(
filename '/data/pgdata/pg_log/postgresql.Mon.csv'
,format 'csv'
,header 'false'
,delimiter ','
,quote '"'
,escape '"'
);
comment on foreign table pg_log_mon is '每周一当天审计日志';
comment on column pg_log_mon.log_time is '日志时间';
comment on column pg_log_mon.user_name is '用户名';
comment on column pg_log_mon.database_name is '数据库名';
comment on column pg_log_mon.process_id is '进程id';
comment on column pg_log_mon.connection_from is '客户端ip:端口';
comment on column pg_log_mon.session_id is '会话id';
comment on column pg_log_mon.session_line_num is '当前会话的第几次查询';
comment on column pg_log_mon.command_tag is '命令类型';
comment on column pg_log_mon.session_start_time is '会话开始时间';
comment on column pg_log_mon.virtual_transaction_id is '虚拟事务id';
comment on column pg_log_mon.transaction_id is '事务id';
comment on column pg_log_mon.error_severity is '错误级别';
comment on column pg_log_mon.sql_state_code is 'sql状态代码';
comment on column pg_log_mon.message is '信息';
comment on column pg_log_mon.detail is '详细信息';
comment on column pg_log_mon.hint is '提示信息';
comment on column pg_log_mon.query is '查询的sql';
comment on column pg_log_mon.application_name is '应用名(客户端名)';
drop foreign table if exists pg_log_tue;
create foreign table pg_log_tue(
log_time timestamp
,user_name text
,database_name text
,process_id integer
,connection_from text
,session_id text
,session_line_num bigint
,command_tag text
,session_start_time timestamp
,virtual_transaction_id text
,transaction_id bigint
,error_severity text
,sql_state_code text
,message text
,detail text
,hint text
,internal_query text
,internal_query_pos integer
,context text
,query text
,query_pos integer
,location text
,application_name text
) server pg_file_server options(
filename '/data/pgdata/pg_log/postgresql.Tue.csv'
,format 'csv'
,header 'false'
,delimiter ','
,quote '"'
,escape '"'
);
comment on foreign table pg_log_tue is '每周二当天审计日志';
comment on column pg_log_tue.log_time is '日志时间';
comment on column pg_log_tue.user_name is '用户名';
comment on column pg_log_tue.database_name is '数据库名';
comment on column pg_log_tue.process_id is '进程id';
comment on column pg_log_tue.connection_from is '客户端ip:端口';
comment on column pg_log_tue.session_id is '会话id';
comment on column pg_log_tue.session_line_num is '当前会话的第几次查询';
comment on column pg_log_tue.command_tag is '命令类型';
comment on column pg_log_tue.session_start_time is '会话开始时间';
comment on column pg_log_tue.virtual_transaction_id is '虚拟事务id';
comment on column pg_log_tue.transaction_id is '事务id';
comment on column pg_log_tue.error_severity is '错误级别';
comment on column pg_log_tue.sql_state_code is 'sql状态代码';
comment on column pg_log_tue.message is '信息';
comment on column pg_log_tue.detail is '详细信息';
comment on column pg_log_tue.hint is '提示信息';
comment on column pg_log_tue.query is '查询的sql';
comment on column pg_log_tue.application_name is '应用名(客户端名)';
drop foreign table if exists pg_log_wed;
create foreign table pg_log_wed(
log_time timestamp
,user_name text
,database_name text
,process_id integer
,connection_from text
,session_id text
,session_line_num bigint
,command_tag text
,session_start_time timestamp
,virtual_transaction_id text
,transaction_id bigint
,error_severity text
,sql_state_code text
,message text
,detail text
,hint text
,internal_query text
,internal_query_pos integer
,context text
,query text
,query_pos integer
,location text
,application_name text
) server pg_file_server options(
filename '/data/pgdata/pg_log/postgresql.Wed.csv'
,format 'csv'
,header 'false'
,delimiter ','
,quote '"'
,escape '"'
);
comment on foreign table pg_log_wed is '每周三当天审计日志';
comment on column pg_log_wed.log_time is '日志时间';
comment on column pg_log_wed.user_name is '用户名';
comment on column pg_log_wed.database_name is '数据库名';
comment on column pg_log_wed.process_id is '进程id';
comment on column pg_log_wed.connection_from is '客户端ip:端口';
comment on column pg_log_wed.session_id is '会话id';
comment on column pg_log_wed.session_line_num is '当前会话的第几次查询';
comment on column pg_log_wed.command_tag is '命令类型';
comment on column pg_log_wed.session_start_time is '会话开始时间';
comment on column pg_log_wed.virtual_transaction_id is '虚拟事务id';
comment on column pg_log_wed.transaction_id is '事务id';
comment on column pg_log_wed.error_severity is '错误级别';
comment on column pg_log_wed.sql_state_code is 'sql状态代码';
comment on column pg_log_wed.message is '信息';
comment on column pg_log_wed.detail is '详细信息';
comment on column pg_log_wed.hint is '提示信息';
comment on column pg_log_wed.query is '查询的sql';
comment on column pg_log_wed.application_name is '应用名(客户端名)';
drop foreign table if exists pg_log_thu;
create foreign table pg_log_thu(
log_time timestamp
,user_name text
,database_name text
,process_id integer
,connection_from text
,session_id text
,session_line_num bigint
,command_tag text
,session_start_time timestamp
,virtual_transaction_id text
,transaction_id bigint
,error_severity text
,sql_state_code text
,message text
,detail text
,hint text
,internal_query text
,internal_query_pos integer
,context text
,query text
,query_pos integer
,location text
,application_name text
) server pg_file_server options(
filename '/data/pgdata/pg_log/postgresql.Thu.csv'
,format 'csv'
,header 'false'
,delimiter ','
,quote '"'
,escape '"'
);
comment on foreign table pg_log_thu is '每周四当天审计日志';
comment on column pg_log_thu.log_time is '日志时间';
comment on column pg_log_thu.user_name is '用户名';
comment on column pg_log_thu.database_name is '数据库名';
comment on column pg_log_thu.process_id is '进程id';
comment on column pg_log_thu.connection_from is '客户端ip:端口';
comment on column pg_log_thu.session_id is '会话id';
comment on column pg_log_thu.session_line_num is '当前会话的第几次查询';
comment on column pg_log_thu.command_tag is '命令类型';
comment on column pg_log_thu.session_start_time is '会话开始时间';
comment on column pg_log_thu.virtual_transaction_id is '虚拟事务id';
comment on column pg_log_thu.transaction_id is '事务id';
comment on column pg_log_thu.error_severity is '错误级别';
comment on column pg_log_thu.sql_state_code is 'sql状态代码';
comment on column pg_log_thu.message is '信息';
comment on column pg_log_thu.detail is '详细信息';
comment on column pg_log_thu.hint is '提示信息';
comment on column pg_log_thu.query is '查询的sql';
comment on column pg_log_thu.application_name is '应用名(客户端名)';
drop foreign table if exists pg_log_fri;
create foreign table pg_log_fri(
log_time timestamp
,user_name text
,database_name text
,process_id integer
,connection_from text
,session_id text
,session_line_num bigint
,command_tag text
,session_start_time timestamp
,virtual_transaction_id text
,transaction_id bigint
,error_severity text
,sql_state_code text
,message text
,detail text
,hint text
,internal_query text
,internal_query_pos integer
,context text
,query text
,query_pos integer
,location text
,application_name text
) server pg_file_server options(
filename '/data/pgdata/pg_log/postgresql.Fri.csv'
,format 'csv'
,header 'false'
,delimiter ','
,quote '"'
,escape '"'
);
comment on foreign table pg_log_fri is '每周五当天审计日志';
comment on column pg_log_fri.log_time is '日志时间';
comment on column pg_log_fri.user_name is '用户名';
comment on column pg_log_fri.database_name is '数据库名';
comment on column pg_log_fri.process_id is '进程id';
comment on column pg_log_fri.connection_from is '客户端ip:端口';
comment on column pg_log_fri.session_id is '会话id';
comment on column pg_log_fri.session_line_num is '当前会话的第几次查询';
comment on column pg_log_fri.command_tag is '命令类型';
comment on column pg_log_fri.session_start_time is '会话开始时间';
comment on column pg_log_fri.virtual_transaction_id is '虚拟事务id';
comment on column pg_log_fri.transaction_id is '事务id';
comment on column pg_log_fri.error_severity is '错误级别';
comment on column pg_log_fri.sql_state_code is 'sql状态代码';
comment on column pg_log_fri.message is '信息';
comment on column pg_log_fri.detail is '详细信息';
comment on column pg_log_fri.hint is '提示信息';
comment on column pg_log_fri.query is '查询的sql';
comment on column pg_log_fri.application_name is '应用名(客户端名)';
drop foreign table if exists pg_log_sat;
create foreign table pg_log_sat(
log_time timestamp
,user_name text
,database_name text
,process_id integer
,connection_from text
,session_id text
,session_line_num bigint
,command_tag text
,session_start_time timestamp
,virtual_transaction_id text
,transaction_id bigint
,error_severity text
,sql_state_code text
,message text
,detail text
,hint text
,internal_query text
,internal_query_pos integer
,context text
,query text
,query_pos integer
,location text
,application_name text
) server pg_file_server options(
filename '/data/pgdata/pg_log/postgresql.Sat.csv'
,format 'csv'
,header 'false'
,delimiter ','
,quote '"'
,escape '"'
);
comment on foreign table pg_log_sat is '每周六当天审计日志';
comment on column pg_log_sat.log_time is '日志时间';
comment on column pg_log_sat.user_name is '用户名';
comment on column pg_log_sat.database_name is '数据库名';
comment on column pg_log_sat.process_id is '进程id';
comment on column pg_log_sat.connection_from is '客户端ip:端口';
comment on column pg_log_sat.session_id is '会话id';
comment on column pg_log_sat.session_line_num is '当前会话的第几次查询';
comment on column pg_log_sat.command_tag is '命令类型';
comment on column pg_log_sat.session_start_time is '会话开始时间';
comment on column pg_log_sat.virtual_transaction_id is '虚拟事务id';
comment on column pg_log_sat.transaction_id is '事务id';
comment on column pg_log_sat.error_severity is '错误级别';
comment on column pg_log_sat.sql_state_code is 'sql状态代码';
comment on column pg_log_sat.message is '信息';
comment on column pg_log_sat.detail is '详细信息';
comment on column pg_log_sat.hint is '提示信息';
comment on column pg_log_sat.query is '查询的sql';
comment on column pg_log_sat.application_name is '应用名(客户端名)';
drop foreign table if exists pg_log_sun;
create foreign table pg_log_sun(
log_time timestamp
,user_name text
,database_name text
,process_id integer
,connection_from text
,session_id text
,session_line_num bigint
,command_tag text
,session_start_time timestamp
,virtual_transaction_id text
,transaction_id bigint
,error_severity text
,sql_state_code text
,message text
,detail text
,hint text
,internal_query text
,internal_query_pos integer
,context text
,query text
,query_pos integer
,location text
,application_name text
) server pg_file_server options(
filename '/data/pgdata/pg_log/postgresql.Sun.csv'
,format 'csv'
,header 'false'
,delimiter ','
,quote '"'
,escape '"'
);
comment on foreign table pg_log_sun is '每周日当天审计日志';
comment on column pg_log_sun.log_time is '日志时间';
comment on column pg_log_sun.user_name is '用户名';
comment on column pg_log_sun.database_name is '数据库名';
comment on column pg_log_sun.process_id is '进程id';
comment on column pg_log_sun.connection_from is '客户端ip:端口';
comment on column pg_log_sun.session_id is '会话id';
comment on column pg_log_sun.session_line_num is '当前会话的第几次查询';
comment on column pg_log_sun.command_tag is '命令类型';
comment on column pg_log_sun.session_start_time is '会话开始时间';
comment on column pg_log_sun.virtual_transaction_id is '虚拟事务id';
comment on column pg_log_sun.transaction_id is '事务id';
comment on column pg_log_sun.error_severity is '错误级别';
comment on column pg_log_sun.sql_state_code is 'sql状态代码';
comment on column pg_log_sun.message is '信息';
comment on column pg_log_sun.detail is '详细信息';
comment on column pg_log_sun.hint is '提示信息';
comment on column pg_log_sun.query is '查询的sql';
comment on column pg_log_sun.application_name is '应用名(客户端名)';
create or replace view pg_log as
select * from pg_log_mon
union all
select * from pg_log_tue
union all
select * from pg_log_wed
union all
select * from pg_log_thu
union all
select * from pg_log_fri
union all
select * from pg_log_sat
union all
select * from pg_log_sun;
更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
每天00:30备份前一天的审计日志
#! /bin/bash
#备份日期默认昨天,也是备份日期上限
BAKUP_DATE_UPPER=`date '+%Y%m%d' -d '-1 day'`
BAKUP_DATE_FLOOR=`date '+%Y%m%d' -d '-6 day'`
BAKUP_DATE=${BAKUP_DATE_UPPER}
showuseage() {
echo "程序功能:在数据库中备份昨天的pg审计日志
Useage: [backup_pglog -h 20220830]
-h [:可选,指定备份日期,可选范围${BAKUP_DATE_FLOOR}-${BAKUP_DATE_UPPER},其他默认昨天]"
}
# /home/postgres/backup_pglog.sh
# 每天备份昨天的数据
while getopts h: OPTS; do
case "$OPTS" in
h)
if [ $OPTARG -ge ${BAKUP_DATE_FLOOR} -a $OPTARG -le ${BAKUP_DATE_UPPER} ]; then
BAKUP_DATE=$OPTARG
fi
;;
:)
echo "$0 必须为 -$OPTARG 添加一个参数!"
exit 1
;;
?)
showuseage
exit 1
;;
esac
done
BAKUP_SQL="
create table if not exists pg_log_:bak_log_span as
select
:today::varchar(8) as bak_date
,*
from pg_log
where 1 = 2
;
delete from pg_log_:bak_log_span where to_char(log_time,'yyyymmdd')::numeric = ${BAKUP_DATE}
;
insert into pg_log_:bak_log_span
select :today::varchar as bak_date ,*
from pg_log
where to_char(log_time,'yyyymmdd')::numeric = ${BAKUP_DATE}
;
"
echo `date '+%Y-%m-%d %H:%m:%S'`"|INFO|备份数据日期:${BAKUP_DATE}"
echo `date '+%Y-%m-%d %H:%m:%S'`"|INFO|审计日志备份开始"
BAKUP_SQL_EXEC_DATE=`date '+%Y%m%d%H%m%S'`
psql <<EOF > /tmp/bakup_sql_exec_${BAKUP_SQL_EXEC_DATE}.log 2>&1
\i ~/var/${BAKUP_DATE}.sql
${BAKUP_SQL}
\q
EOF
EXECLOG=`cat /tmp/bakup_sql_exec_${BAKUP_SQL_EXEC_DATE}.log`
rm -f /tmp/bakup_sql_exec_${BAKUP_SQL_EXEC_DATE}.log
echo `date '+%Y-%m-%d %H:%m:%S'`"|INFO|审计日志备份结束"
# 错误
ERRORNUM=`echo "${EXECLOG}" | grep -i 'ERROR' | wc -l`
if [ ${ERRORNUM} -eq 0 ]
then
# 发短信通知备份成功
echo `date '+%Y-%m-%d %H:%m:%S'`"|INFO|审计日志备份成功"
exit 0
else
# 发短信通知备份失败
echo "请及时重新执行备份脚本进行备份" | mail -s "审计日志备份失败" 1445471277@qq.com
echo `date '+%Y-%m-%d %H:%m:%S'`"|ERROR|审计日志备份失败"
exit 1
fi
chmod +x /home/postgres/backup_pglog.sh
crontab -e
30 0 * * * . /home/postgres/backup_pglog.sh >> /home/postgres/backup_pglog.log 2>&1
%a #星期的英文单词的缩写:如星期一, 则返回 Mon
%A #星期的英文单词的全拼:如星期一,返回 Monday
%b #月份的英文单词的缩写:如一月, 则返回 Jan
%B #月份的引文单词的缩写:如一月, 则返回 January
%c #返回datetime的字符串表示,如03/08/15 23:01:26
%d #返回的是当前时间是当前月的第几天
%f #微秒的表示: 范围: [0,999999]
%H #以24小时制表示当前小时
%I #以12小时制表示当前小时
%j #返回 当天是当年的第几天 范围[001,366]
%m #返回月份 范围[0,12]
%M #返回分钟数 范围 [0,59]
%P #返回是上午还是下午–AM or PM
%S #返回秒数 范围 [0,61]。。。手册说明的
%U #返回当周是当年的第几周 以周日为第一天
%W #返回当周是当年的第几周 以周一为第一天
%w #当天在当周的天数,范围为[0, 6],6表示星期天
%x #日期的字符串表示 :03/08/15
%X #时间的字符串表示 :23:22:08
%y #两个数字表示的年份 15
%Y #四个数字表示的年份 2015
%z #与utc时间的间隔 (如果是本地时间,返回空字符串)
%Z #时区名称(如果是本地时间,返回空字符串)
更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
mpstat | sed -n '3,$p' | awk -F' ' '{print $13}'
echo 'CPU CORE' && cat /proc/cpuinfo|grep processor|wc -l
正常:空闲cpu大于20%;
异常处理:排查问题,杀掉cpu高进程,top 按c;
free -m
正常:空闲内存大于30%;
异常处理:排查问题,杀掉内存高进程,top 按c;
df -lh
正常:磁盘空间已用空间小于70%;
异常处理:增加硬盘或者删除无用的数据;
iostat -x | sed -n '6,$p' | awk -F' ' '{print $1,$13,$14}'
正常:磁盘空间已用空间小于70%;
异常处理:增加硬盘或者删除无用的数据;
netstat -tanp | grep 'LISTEN' | grep '5432'
正常:tcp4和tcp6正常监听;
异常处理:排查数据库是否正常启动,排查数据库配置文件的端口参数是否为5432;
ps -ef | grep "checkpointer|background writer|walwriter|autovacuum launcher|archiver|stats collector|logical replication launcher|logger" | grep -v grep
正常:进程都在;
异常处理:重启数据库;
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(运行时长)"
--,inet_server_addr() "server_ip(服务器ip)"
--,inet_server_port() "server_port(服务器端口)"
--,inet_client_addr() "client_ip(客户端ip)"
--,inet_client_port() "client_port(客户端端口)"
,version() "server_version(数据库版本)"
,(case when pg_is_in_recovery()='f' then 'primary' else 'standby' end ) as "primary_or_standby(主或备)"
;
正常:数据库正常使用;
异常处理:重装数据库;
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,sourceline "sourceline(行号)"
,name "para(参数名)"
,setting "value(参数值)"
from pg_file_settings
order by "sourceline(行号)";
正常:各项参数设置适合;
异常处理:编辑postgresql.conf文件,修改参数后重启数据库;
vi $PGDATA/postgresql.conf
pg_ctl restart -mf
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(行号)";
正常:非套接字连接都需要md5认证;
异常处理:编辑pg_hba.conf文件,修改参数后重新加载数据库;
vi $PGDATA/postgresql.conf
pg_ctl reload
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;
正常:各项配置都适合;
异常处理:修改不合适的配置;
主
select
-- pid "pid(进程id)"
--,usename "username(用户名)"
--,application_name "application_name(应用名)"
--,client_addr "client_addr(IP)"
--,backend_start "backend_start(备份开始时间)"
state "state(WAL发送状态编码)"
-- ,case
-- when state = 'startup' then '正在启动'
-- when state = 'catchup' then '追赶主库'
-- when state = 'streaming' then '流传送'
-- when state = 'backup' then '发送备份'
-- when state = 'stopping' then '发送停止'
-- end "statename(WAL状态)"
,sync_state "sync_state(同步状态编码)"
-- ,case
-- when sync_state = 'async' then '异步'
-- when sync_state = 'potential' then '后备失效变同步'
-- when sync_state = 'sync' then '同步'
-- when sync_state = 'quorum' then '候选'
-- end "sync_statename(同步状态名称)"
--,round(pg_wal_lsn_diff(pg_current_wal_lsn(),replay_lsn) /(1024 * 1024),2) as "slave_latency_mb(同步延迟_MB)"
from pg_stat_replication;
从
select
-- pid "pid(进程id)"
status "status(WAl接收状态)"
,'async' "sync_state(同步状态编码)"
--,last_msg_send_time "last_msg_send_time(接收到最后的消息发送时间)"
--,last_msg_receipt_time "last_msg_receipt_time(接收到最后的消息接收时间)"
--,sender_host "sender_host(主库IP)"
from pg_stat_wal_receiver
;
更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,spcname AS "Name(名称)"
,pg_catalog.pg_get_userbyid(spcowner) AS "Owner(拥有者)"
--,pg_catalog.pg_tablespace_location(oid) AS "Location(数据文件目录)"
--,pg_catalog.array_to_string(spcacl, E'\n') AS "Access privileges(访问权限)"
--,spcoptions AS "Options(参数)"
,pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS "Size(表空间大小)"
--,pg_catalog.shobj_description(oid, 'pg_tablespace') AS "Description(备注)"
from pg_catalog.pg_tablespace
order by 1;
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
;
正常:连接数不超过总连接数的90%;
异常处理:超级用户(postgres)杀连接;
--杀掉所有空闲连接
select pg_terminate_backend(pid) from pg_stat_activity WHERE state = 'idle';
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,relname "relname(表名)"
,b.nspname "shemaname(模式名)"
,c.rolname "user(用户名)"
,d.locktype "locktype(被锁对象类型)"
,d.mode "mode(锁类型)"
,d.pid "pid(进程id)"
,e.query "query(锁表sql)"
,current_timestamp-state_change "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 = 'AccessExclusiveLock'
order by "lock_duration(锁表时长)" desc;
正常:无锁表;
异常处理:取消该进程或杀掉该会话;
--取消该进程
select pg_cancel_backend(pid);
--杀掉该会话
select pg_terminate_backend(pid);
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,a.datname "datname(数据库名)"
,a.pid "pid(进程id)"
,b.rolname "username(用户名)"
--,a.application_name "app_name(应用名称)"
,a.client_addr "client_ip(客户端ip)"
--,a.query_start "query_start(当前查询开始时间)"
,to_char(a.state_change,'yyyy-mm-dd hh24:mi:ss') "state_change(状态变化时间)"
--,a.state "state(状态)"
--,a.query "sql(执行的sql)"
--,a.backend_type "backend_type(后端类型)"
from pg_stat_activity a
inner join pg_roles b
on (a.usesysid = b.oid)
where a.state = 'idle'
and state_change < current_timestamp - interval '30 min'
order by current_timestamp-state_change desc
limit 5
;
正常:超半小时空闲的连接;
异常处理:杀连接;
select pg_terminate_backend(pid);
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,a.datname "datname(数据库名)"
,a.pid "pid(进程id)"
,b.rolname "username(用户名)"
--,a.application_name "app_name(应用名称)"
,a.client_addr "client_ip(客户端ip)"
--,a.xact_start "xact_start(当前事务开始时间)"
--,a.query_start "query_start(当前查询开始时间)"
,to_char(a.state_change,'yyyy-mm-dd hh24:mi:ss') "state_change(状态变化时间)"
--,a.state "state(状态)"
--,a.query "sql(执行的sql)"
--,a.backend_type "backend_type(后端类型)"
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 state_change < current_timestamp - interval '30 min'
order by current_timestamp-state_change desc
limit 5;
正常:不存在长事务;
异常处理:杀会话;
select pg_terminate_backend(pid);
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,a.datname "datname(数据库名)"
,a.pid "pid(进程id)"
,b.rolname "username(用户名)"
--,a.application_name "app_name(应用名称)"
,a.client_addr "client_ip(客户端ip)"
--,a.query_start "query_start(当前查询开始时间)"
,to_char(a.state_change,'yyyy-mm-dd hh24:mi:ss') "state_change(状态变化时间)"
--,a.wait_event_type "wait_event_type(等待类型)"
--,a.wait_event "wait_event(等待事件)"
--,a.state "state(状态)"
--,a.query "sql(执行的sql)"
--,a.backend_type "backend_type(后端类型)"
from pg_stat_activity a
left join pg_roles b
on (a.usesysid = b.oid)
where a.state = 'active'
and state_change < current_timestamp - interval '1 hour'
and a.datname is not null
order by current_timestamp-state_change desc
limit 5;
正常:不存在慢sql;
异常处理:分析原因,有针对性地杀连接;
select pg_terminate_backend(pid);
--这里需要循环查每个库所有数据然后合并
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万;
异常处理:删除无用的对象;
select
to_char(now(),'yyyy-mm-dd hh24:mi:ss') "巡检时间"
,current_database() current_database
,relname as "table_name(表名)"
,schemaname as "schema_name(模式名)"
,pg_size_pretty(pg_relation_size('"'||schemaname|| '"."'||relname||'"')) 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/(n_live_tup+n_dead_tup)*100,2),'fm990.00') as "dead_rate(无效记录比例%)"
from
pg_stat_all_tables
where n_live_tup+n_dead_tup <> 0
;
正常:不存在表膨胀,因为有自动清理垃圾进程;
异常处理:对膨胀表做vacuum analyze操作;
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 -- very rough approximation, assumes all cols
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
;
索引膨胀,依赖于统计信息,统计信息未更新,索引膨胀信息不准确。一般每年统一做一次重建索引即可。
异常处理:重建索引;
reindex index 索引名;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。