源码安装
root@server01:~# mkdir /apps/pgsql/
./configure --prefix=/apps/pgsql
make world -j4
make install-world
useradd -s /bin/bash -m -d /home/postgres postgres
echo -e '123456\n123456' | passwd postgres
mkdir -pv /pgsql/data
chown postgres:postgres /pgsql/data/
设置环境变量
bash
vim /etc/profile.d/pgsql.sh
export PGHOME=/apps/pgsql
export PATH=$PGHOME/bin/:$PATH
export PGDATA=/pgsql/data
export PGUSER=postgres
export MANPATH=/apps/pgsql/share/man:$MANPATH
初始化
su - postgres
initdb -D /pgsql/data/
pg_ctl -D /pgsql/data/ -l logfile start
连接
psql
Ubuntu 启动脚本实现开机自动PostgreSQL
方法一
root@server02:~/postgresql-14.2/contrib# vim start-scripts/linux #修改安装目录和数据目录
prefix=/apps/pgsql
#Data directory
PGDATA="/pgsql/data"
root@server02:~/postgresql-14.2/contrib# cp start-scripts/linux /etc/init.d/postgresql
root@server02:~/postgresql-14.2/contrib# chmod +x /etc/init.d/postgresql
vi /etc/rc.local
/etc/init.d/postgresql start
方法二
su - postgres -c "/apps/pgsql/bin/pg_ctl -D /pgsql/data/ -l logfile start"
service文件启动
bash
root@server02:/apps/pgsql# cat /lib/systemd/system/postgresql.service
[Unit]
Description=PostgreSQL database server
After=network.target
[Service]
User=postgres
Group=postgres
ExecStart=/apps/pgsql/bin/postmaster -D /pgsql/data
ExecReload=/bin/kill -HUP
[Install]
WantedBy=multi-user.target
POSTgresql管理
导入数据:psql -f pg.sql
cat pg.sql
create database luo;
\c luo;
create table test(id int);
配置远程连接
改配置文件,修改监听端口为0.0.0.0
listen_addresses = '0.0.0.0'
psql -h 120.77.146.92 -U postgres
psql: error: connection to server at "120.77.146.92", port 5432 failed: FATAL: no pg_hba.conf entry for host "120.79.60.104", user "postgres", database "postgres", no encryption
配置连接文件,ubuntu yum安装在 /etc/postgresql/14/main/pg_hba.conf
vi pg_hba.conf
host all all 0.0.0.0/0 trust 远程不用密码
host all all 0.0.0.0/0 md5 #要密码,添加此行
重启服务:pg_ctl -D /pgsql/data/ restart
修改用户密码
alter user postgres with password '123456';
远程连接成功
psql -h 120.79.60.104 -U postgres -p 5432
免密连接
cat .pgpass
120.79.60.104:5432:db1:postgres:12345
psql -h 120.79.60.104 db1 postgres
\timing on #显示执行命令时间
\set VERBOSITY VERBOSE ##显示详细的信息,可以打印出报出问题的源代码位置
bash
查看数据库存放目录的路径
select oid,datname from pg_database;
create schema n80_sch; #创建schema
db1=# \dn #查看schema
create table n80_sch.t1(id int); #创建 表属于n80_sch
\dt n80_sch.t1 #查看
db1=# \dt n80_sch.t1
List of relations
Schema | Name | Type | Owner
---------+------+-------+----------
n80_sch | t1 | table | postgres
sql
b1=# \c testdb #切换数据库
testdb=# insert into tb1 (name) select (md5(random()::text)) from generate_series (2,10);
create table tb2 (like tb1); ##复制表结构,不复制数据
\d tb2 查看表结果
select * from pg_tables; #查看所有的表
select pg_total_relation_size('tb1');#查看表大小
查看数据库对应的目录
testdb=# select oid,datname from pg_database where datname = 'testdb';
oid | datname
-------+---------
16409 | testdb
(1 row)
查看表对应的文件
testdb=# select relid from pg_stat_all_tables where relname='tb1';
relid
-------
16411
root@server02:/pgsql/data/base/16409# ll 16411
-rw------- 1 postgres postgres 8192 Aug 20 12:41 16411
或者
testdb=# select * from pg_relation_filepath('tb1');
base/16409/16411
查看当前库中的所有表的统计信息
select * from pg_stat_all_tables;
#查看指定表t1的信息
select * from pg_stat_all_tables where relname='t1';
create table tb1 (id serial,name varchar(10));
批量添加
sql
testdb=# create table tb1 (id serial primary key,name text);
CREATE TABLE
Time: 5.048 ms
testdb=# insert into tb1 (name) select (md5(random()::text)) from
generate_series (1,1000000);
INSERT 0 1000000
Time: 3638.546 ms (00:03.639)
100万记录2秒
sql
testdb=# create table tb1(id int,info text,crt_time timestamp);
CREATE TABLE
Time: 3.263 ms
testdb=# insert into tb1 select
generate_series(1,100000),md5(random()::text),clock_timestamp();
INSERT 0 100000
显示时间
testdb=# select clock_timestamp();
2023-08-20 13:09:20.561662+08
#创建索引
testdb=# create index idx_tb1_id on tb1(id);
#查看索引
select * from pg_indexes where tablename='tb1';
#查询条件是索引列
testdb=# explain analyze select * from tb1 where id = 99999;
Index Scan using idx_tb1_id on tb1 (cost=0.29..8.31 rows=1 width=45) (actual time=0.020..0.021 rows=1 loops=1)
Index Cond: (id = 99999)
Planning Time: 0.198 ms
Execution Time: 0.041 ms
Time: 0.412 ms
全表扫描
testdb=# explain analyze select * from tb1 where info =
'fb16d90265f55880ba96b016afe65b51 ';
Seq Scan on tb1 (cost=0.00..2185.00 rows=1 width=45) (actual time=7.967..7.968 rows=0 loops=1)
Filter: (info = 'fb16d90265f55880ba96b016afe65b51 '::text)
Rows Removed by Filter: 100000
Planning Time: 0.058 ms
Execution Time: 7.986 ms
Time: 8.359 ms
#关闭索引
testdb=# set enable_indexscan=off;
SET
set enable_bitmapscan=off;
删除索引
testdb=# drop index idx_tb1_id;
表空间
存放表的目录
postgres@server02:~$ mkdir ts1
testdb=# create tablespace ts1 location '/home/postgres/ts1/';
CREATE TABLESPACE
Time: 1.256 ms
testdb=# \db
pg_default | postgres |
pg_global | postgres |
ts1 | postgres | /home/postgres/ts1
创建表指定表空间
create table tb3(id int) tablespace ts1;
testdb=# select * from pg_relation_filepath('tb3');
pg_tblspc/16448/PG_14_202107181/16409/16449
删除表空间,要先删除表
drop tablespace ts1;
#查看数据库启动时间
postgres=# select pg_postmaster_start_time();
导入数据
psql < hellodb.sql
#关闭自动提交,可以用rollback取消DML语句
\set AUTOCOMMIT off
\set AUTOCOMMIT on
用户账号管理
python
Create user user1 PASSWORD '123';
CREATE ROLE li WITH LOGIN PASSWORD '123456';
登录
psql -h 120.79.60.104 -U user1 hellodb
创建超级管理员,可以删除库
CREATE ROLE luo WITH SUPERUSER LOGIN PASSWORD '123456' ;
禁止登录
alter user luo with nologin ;
\du 查看用户信息
修改用户有创建数据库权限
postgres=# alter user li with createdb;
授权li用户hellodb数据库查看权限
pinxixi=# \c hellodb
You are now connected to database "hellodb" as user "postgres".
hellodb=# GRANT select ON ALL TABLES IN schema public to li;
GRANT
安装pgadmin
apt list|grep pgadmin
apt install phppgadmin
wal 日志
Online WAL(WRITE-AHEAD LOG)日志功能是为了保证崩溃后的安全,如果系统崩溃,可以"重放"从最
后一次检查点以来的日志项来恢复数据库的一致性。但是也存在日志膨胀的问题,相当于MySQL的事务日
志redo log
#查看当前日志文件lsn位置;
select pg_current_wal_lsn();
查看wal日志位置
root@server02:~# ll /pgsql/data/pg_wal/ -t
#查看事务ID
postgres=# select txid_current();
txid_current
820
查看 WAL 文件内容
pg_waldump /pgsql/data/pg_wal/000000010000000000000018
rmgr: XLOG len (rec/tot): 114/ 114, tx: 0, lsn: 0/18000328, prev 0/180002F0, desc: CHECKPOINT_ONLINE redo 0/180002F0; tli 1; prev tli 1; fpw true; xid 0:819; oid 16519; multi 1; offset 0; oldest xid 726 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 819; online
rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/180003A0, prev 0/18000328, desc: RUNNING_XACTS nextXid 819 latestCompletedXid 818 oldestRunningXid 819
rmgr: Transaction len (rec/tot): 34/ 34, tx: 819, lsn: 0/180003D8, prev 0/180003A0, desc: COMMIT 2023-08-21 22:00:22.279472 CST
rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/18000400, prev 0/180003D8, desc: RUNNING_XACTS nextXid 820 latestCompletedXid 819 oldestRunningXid 820
pg_waldump: fatal: error in WAL record at 0/18000400: invalid record length at 0/18000438: wanted 24, got 0
#按时间排序显示WAL文件名
select * from pg_ls_waldir() order by modification asc;
#默认WAL文件达到16M,自动切换另一个WAL
切换 WAL 日志
select pg_switch_wal();
归档wal日志
把wal日志归档到本地或远程目录
归档日志记录的是checkpoint前的WAL日志,即数据的历史日志,即把pg_wal里面的在线日志备份出来,功能上归档日志相当于MySQL的二进制日志
生产环境中为了保证数据高可用性,通常需要开启归档,当系统故障后可以通过归档的日志文件对数据进行恢复
#配置归档需要开启如下参数:
wal_level = replica
#该参数的可选的值有minimal, replica和logical,wal的级别依次增高,在wal的信息也越多。由于
minimal这一级别的wal不包含从基础的备份和wal日志重建数据的足够信息,在该模式下,无法开启wal日志
归档
#从PostgreSQL 10开始,默认使用的replica此级别,也建议使用此级别,之前版本默认是最小级别
minimal
archive_mode = on
#上述参数为on,表示打开归档备份,可选的参数为on,off,always 默认值为off,所以要手动打开,需要重
启服务生效
开启归档日志
#在 PostgreSQL中配置归档的方法是配置参数 archive_command,参数的配置值可以是一个Unix命令,
此命令把WAL日志文档拷贝到其他地方
postgres@server02:/pgsql/data$ vi postgresql.conf
archive_mode = on # enables archiving; off, on, or always
archive_command = '[ ! -f /archive/%f ] && cp %p /archive/%f'
#用"%p"表示将要归档的wal文件包含完整路径的信息的文件名
#用"%f"代表不包含路径信息的wal文件的文件名
创建文件并授权
root@server02:/pgsql/data# mkdir /archive
root@server02:/pgsql/data# chown postgres:postgres /archive/
切换日志 select pg_switch_wal(); 会拷贝到/archive/
root@server02:/pgsql/data# ls /archive
000000010000000000000018
拷贝到远程
面密钥
postgres@server02:/pgsql/data$ ssh-keygen
postgres@server02:/pgsql/data$ ssh-copy-id postgres@172.29.21.67
修改配置
postgres@server02:/pgsql/data$ vi postgresql.conf
archive_command = 'scp %p postgres@172.29.21.67:/pgsql/backup/%f'
目标主机创建目录授权
root@server01:~# mkdir /pgsql/backup -p
oot@server01:~# chown postgres:postgres /pgsql/backup/ -R
重启
postgres@server02:/pgsql/data$ pg_ctl restart
postgres=# select pg_switch_wal();
#在备份服务器上可看到日志的备份出现
ls /pgsql/backup/
PostgreSQL 备份恢复
逻辑备份
PostgreSQL提供了pg_dump、pg_dumpall 命令进行数据库的逻辑备份。
两者的功能差不多,只是pg_dumpall 是将一个PostgreSQL数据库集群全部转储到一个脚本文件中,而
pg_dump命令可以选择一个数据库或部分表进行备份。
另外利用COPY命令也能对表和SQL子集进行备份,实现表的还原
远程备份
root@server01:~# pg_dump -h 172.16.141.0 -U postgres -f /backup/hellodb hellodb
远程还原到hui数据库
psql -h 172.16.141.0 -U postgres -d hui < /backup/hellodb
本地
psql -d luo < /backup/hellodb
备份 hellodb数据库, -C 会备份创建数据库的命令,可以直接还原
root@server01:~# pg_dump -h 172.16.141.0 -U postgres -f /backup/hellodb3 -C hellodb
删除数据库
hui=# drop database hellodb;
还原
psql -h 172.16.141.0 -U postgres < /backup/hellodb3
#如果想生成的备份文件格式为自定义格式,可以使用下面的命令:
-F自定义文件格式
root@server01:~# pg_dump -Fc -h 172.16.141.0 -U postgres -C hellodb -f /backup/hellodb.dump
要先在恢复机器创建数据库
create database hellodb2;
pg_restore -h 172.16.141.0 -U postgres -d hellodb2 < /backup/hellodb.dump
备份所有数据库,每个数据库要输入密码
root@server01:~# pg_dumpall -h 172.16.141.0 -U postgres -f /backup/all_pgsql.sql
授权postgres用户对db2库有所有权限
GRANT ALL PRIVILEGES ON DATABASE db2 TO postgres;
bash
导出为csv文件
hellodb2=# copy students TO '/tmp/students.csv' with csv;
COPY 25
hellodb2=# delete from students;
DELETE 25
hellodb2=# select * from students;
stuid | name | age | gender | classid | teacherid
-------+------+-----+--------+---------+-----------
(0 rows)
hellodb2=# copy students from '/tmp/students.csv' with csv;
COPY 25
hellodb2=# select * from students;
stuid | name | age | gender | classid | teacherid
-------+---------------+-----+--------+---------+-----------
1 | Shi Zhongyu | 22 | M | 2 | 3
2 | Shi Potian | 22 | M | 1 | 7
导出导入指定字段
bash
hellodb2=# copy students from '/tmp/students.csv' with csv;
hellodb2=# create table students2(id int ,name char (30));
hellodb2=# COPY students2 from '/tmp/students.csv' WITH csv;
hellodb2=# select * from students2;
id | name
----+--------------------------------
1 | Shi Zhongyu
导出带字段名
hellodb2=# COPY students2 to '/tmp/students.csv' WITH csv header;
导入
COPY students2 from '/tmp/students.csv' WITH csv header;
物理备份
postgres@server02:/pgsql/data$ pg_ctl stop
waiting for server to shut down... done
server stopped
备份
root@server02:/pgsql/data# cp -ap /pgsql/data /backup/20230822pgsql
启动
postgres@server02:/pgsql/data$ pg_ctl start
删除数据库postgres=# drop database hellodb2;
还原
postgres@server02:/pgsql/data$ pg_ctl stop
root@server02:/backup# rm -rf /pgsql/data/*
cp -a /backup/20230822pgsql2/* /pgsql/data/
postgres@server02:/pgsql/data$ pg_ctl start
验证数据库是否恢复
利用PITR实现误删除的实战案例
bash
首先备份数据
pg_basebackup -D /pgsql/backupliu -Ft -Pv -U postgres -h 172.16.141.0 -p5432 -R
root@server01:/pgsql/data/log# ls /pgsql/backupliu
16448.tar backup_manifest base.tar pg_wal.tar
数据更新#在PG服务器上继续生成测试数据
testdb=# insert into t1 values(2);
#模拟数据库删除
postgres=# drop database testdb;
查看日志文件
postgres=# select pg_walfile_name(pg_current_wal_lsn());
pg_walfile_name
--------------------------
00000002000000000000004D
(1 row)
postgres=# select txid_current();
txid_current
--------------
1054
(1 row
切换归档日志
postgres=# select pg_switch_wal();
pg_switch_wal
---------------
0/4D0000D8
(1 row)
恢复
postgres@server01:~$ tar -xf /pgsql/backupliu/base.tar -C /pgsql/data
拷贝到从节点
root@server02:/archive# scp * 172.29.21.67:/archive/
#查看故障点事务ID
pg_waldump /archive/pg_waldump /archive/000000020000000000000020 |grep -B10
"DROP dir"
查看事务id 1053
#修改配置文件postgresql.conf,或者postgresql.auto.conf文件也可以[postgres@backup ~]$vi /pgsql/data/postgresql.conf
#加下面两行
restore_command ='cp /archive/%f %p'
#指定还原至上面查到的事务ID
recovery_target_xid ='1053'
启动服务
重节点启动时
查看日志
root@server01:/pgsql/data/log# cat postgresql-2023-08-24_004446.log
2023-08-24 00:44:46.549 CST [271757] LOG: ending log output to stderr
2023-08-24 00:44:46.549 CST [271757] HINT: Future log output will go to log destination "csvlog".
cp: cannot stat '/archive/00000003.history': No such file or directory
cp: cannot open '/archive/00000002.history' for reading: Permission denied
cp: cannot open '/archive/00000002000000000000004C' for reading: Permission denied
cp: cannot stat '/archive/00000003.history': No such file or directory
cp: cannot open '/archive/00000002.history' for reading: Permission denied
注意权限
root@server01:/pgsql/data/log# chown postgres.postgres /archive/ -R
PostgreSQL 高可用
开启wal归档日志
Master 节点配置
创建并授权用户
create role repluser with replication login password '123456';
#修改pg_hba.conf进行授权
[postgres@master ~]$vi /pgsql/data/pg_hba.conf
host replication repluser 0.0.0.0/0 md5
从节点
bash
pg_ctl stop -D /pgsql/data
rm -rf /pgsql/data/*
rm -rf /archive/*
rm -rf /backup/*
rm -rf /pgsql/backup/*
pg_basebackup -D /pgsql/backup/ -Ft -Pv -Urepluser -h 172.16.141.0 -p 5432 -R
tar xf /pgsql/backup/base.tar -C /pgsql/data
tar xf /pgsql/backup/pg_wal.tar -C /archive/
ls -l /pgsql/data
vi /pgsql/data/postgresql.auto.conf
vi /pgsql/data/postgresql.conf
pg_ctl -D /pgsql/data start
主库查看
主从切换
主
bash
[postgres@slave ~]$pg_ctl promote
waiting for server to promote.... done
server promoted
[postgres@slave ~]$pg_controldata
[postgres@rocky8 ~]$pg_ctl restart
从
postgres@server02:~$ pg_ctl stop
waiting for server to shut down... done
server stopped
postgres@server02:~$ rm -rf /pgsql/data/*
postgres@server02:~$ rm -rf /archive/*
postgres@server02:~$ rm -rf /pgsql/backup/
postgres@server02:~$ pg_basebackup -D /pgsql/backup/ -Ft -Pv -Urepluser -h 172.29.21.67 -p 5432 -R
postgres@server02:~$ tar -xf /pgsql/backup/base.tar -C /pgsql/data/
postgres@server02:~$ tar -xf /pgsql/backup/pg_wal.tar -C /archive/
修改配置,修改host
postgres@server02:~$ vi /pgsql/data/postgresql.conf
primary_conninfo ='host=172.29.21.67 port=5432 user=repluser password=123456'
restore_command ='cp /archive/%f %p'
postgres@server02:~$ pg_ctl -D /pgsql/data/ start
bash
主库测试写入正常
hellodb=> delete from teachers where tid=3;
DELETE 1
hellodb=> create table test(id int);
CREATE TABLE
hellodb=> select * from test;
id
----
(0 rows)
hellodb=> insert into test values (1);
INSERT 0 1
实现同步的流复制
vi /pgsql/data/postgresql.conf
synchronous_standby_names = '*' #开启此项,表示同步方式,默认是异步方式
synchronous_commit = on #开启同步模式