yum install -y vim lrzsz tree wget gcc gcc-c++ readline-devel zlib-devel
进入/usr/local/目录下:cd /usr/local
下载 tar 包:curl -O https://ftp.postgresql.org/pub/source/v16.2/postgresql-16.2.tar.gz
解压:tar -xzvf postgresql-16.2.tar.gz
编译安装:
1 2 3 4 5
cd /usr/local/postgresql-16.2 ./configure --prefix=/usr/local/pgsql-16.2 # /usr/local/pgsql-16.2 为安装目录 make && make install # Two thousand years later,出现「PostgreSQL installation complete.」代表安装成功
# This is an example of a start/stop script for SysV-style init, such # as is used on Linux systems. You should edit some of the variables # and maybe the 'echo' commands. # # Place this file at /etc/init.d/postgresql (or # /etc/rc.d/init.d/postgresql) and make symlinks to # /etc/rc.d/rc0.d/K02postgresql # /etc/rc.d/rc1.d/K02postgresql # /etc/rc.d/rc2.d/K02postgresql # /etc/rc.d/rc3.d/S98postgresql # /etc/rc.d/rc4.d/S98postgresql # /etc/rc.d/rc5.d/S98postgresql # Or, if you have chkconfig, simply: # chkconfig --add postgresql # # Proper init scripts on Linux systems normally require setting lock # and pid files under /var/run as well as reacting to network # settings, so you should treat this with care.
# Original author: Ryan Kirkpatrick <pgsql@rkirkpat.net>
# Data directory PGDATA="/home/postgres/db_data" ###### 下面不改 #####################
# Who to run postgres as, usually "postgres". (NOT "root") PGUSER=postgres
# Where to keep a log file PGLOG="$PGDATA/serverlog"
# It's often a good idea to protect the postmaster from being killed by the # OOM killer (which will tend to preferentially kill the postmaster because # of the way it accounts for shared memory). To do that, uncomment these # three lines: #PG_OOM_ADJUST_FILE=/proc/self/oom_score_adj #PG_MASTER_OOM_SCORE_ADJ=-1000 #PG_CHILD_OOM_SCORE_ADJ=0 # Older Linux kernels may not have /proc/self/oom_score_adj, but instead # /proc/self/oom_adj, which works similarly except for having a different # range of scores. For such a system, uncomment these three lines instead: #PG_OOM_ADJUST_FILE=/proc/self/oom_adj #PG_MASTER_OOM_SCORE_ADJ=-17 #PG_CHILD_OOM_SCORE_ADJ=0
## STOP EDITING HERE
# The path that is to be used for the script PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# What to use to start up postgres. (If you want the script to wait # until the server has started, you could use "pg_ctl start" here.) DAEMON="$prefix/bin/postgres"
# What to use to shut down postgres PGCTL="$prefix/bin/pg_ctl"
set -e
# Only start if we can find postgres. test -x $DAEMON || { echo"$DAEMON not found" if [ "$1" = "stop" ] thenexit 0 elseexit 5 fi }
# If we want to tell child processes to adjust their OOM scores, set up the # necessary environment variables. Can't just export them through the "su". if [ -e "$PG_OOM_ADJUST_FILE" -a -n "$PG_CHILD_OOM_SCORE_ADJ" ] then DAEMON_ENV="PG_OOM_ADJUST_FILE=$PG_OOM_ADJUST_FILE PG_OOM_ADJUST_VALUE=$PG_CHILD_OOM_SCORE_ADJ" fi
#!/bin/bash # THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES # # It is highly advisable to create own systemd services or udev rules # to run scripts during boot instead of using this file. # # In contrast to previous versions due to parallel execution during boot # this script will NOT be run after all other services. # # Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure # that this script will be executed during boot. exec 2> /tmp/rc.local.log # send stderr from rc.local to a log file exec 1>&2 # send stdout to the same log file echo"rc.local starting..."# show start of execution set -x
touch /var/lock/subsys/local
cd /etc/rc.d/init.d/ sudo sh postgresql start & # 以root执行,不然可能会出现权限错误,&表示后台执行 # 脚本执行完后也给个日志 echo"rc.local completed"
declare begin case i_mode when'INVALID'thenreturn0; when'AccessShareLock'thenreturn1; when'RowShareLock'thenreturn2; when'RowExclusiveLock'thenreturn3; when'ShareUpdateExclusiveLock'thenreturn4; when'ShareLock'thenreturn5; when'ShareRowExclusiveLock'thenreturn6; when'ExclusiveLock'thenreturn7; when'AccessExclusiveLock'thenreturn8; elsereturn0; endcase; end;
$$ language plpgsql strict;
-- 2. 修改查询语句,按锁级别排序: with t_wait as (select a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.objid,a.objsubid, a.pid,a.virtualtransaction,a.virtualxid,a,transactionid,b.query,b.xact_start,b.query_start, b.usename,b.datname from pg_locks a,pg_stat_activity b where a.pid=b.pid andnot a.granted), t_run as (select a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.objid,a.objsubid, a.pid,a.virtualtransaction,a.virtualxid,a,transactionid,b.query,b.xact_start,b.query_start, b.usename,b.datname from pg_locks a,pg_stat_activity b where a.pid=b.pid and a.granted) select r.locktype,r.mode r_mode,r.usename r_user,r.datname r_db,r.relation::regclass,r.pid r_pid, r.page r_page,r.tuple r_tuple,r.xact_start r_xact_start,r.query_start r_query_start, now()-r.query_start r_locktime,r.query r_query,w.mode w_mode,w.pid w_pid,w.page w_page, w.tuple w_tuple,w.xact_start w_xact_start,w.query_start w_query_start, now()-w.query_start w_locktime,w.query w_query from t_wait w,t_run r where r.locktype isnotdistinctfrom w.locktype and r.database isnotdistinctfrom w.database and r.relation isnotdistinctfrom w.relation and r.page isnotdistinctfrom w.page and r.tuple isnotdistinctfrom w.tuple and r.classid isnotdistinctfrom w.classid and r.objid isnotdistinctfrom w.objid and r.objsubid isnotdistinctfrom w.objsubid and r.transactionid isnotdistinctfrom w.transactionid and r.pid <> w.pid orderby f_lock_level(w.mode)+f_lock_level(r.mode) desc,r.xact_start;
现在可以排在前面的就是锁级别高的等待,优先干掉这个。
-[ RECORD 1 ]-+----------------------------------------------------------
-- 按从大到小排序输出数据库每个索引大小 select indexrelname, pg_size_pretty(pg_relation_size(indexrelid)) as size from pg_stat_user_indexes where schemaname='public'orderby pg_relation_size('public'||'.'||indexrelname) desc;
-- [PostgreSQL中查询 每个表的总大小、索引大小和数据大小,并按总大小降序排序](https://blog.csdn.net/sunny_day_day/article/details/131455635) SELECT pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size, pg_size_pretty(pg_indexes_size(c.oid)) AS index_size, pg_size_pretty(pg_total_relation_size(c.oid) - pg_indexes_size(c.oid)) AS data_size, nspname AS schema_name, relname AS table_name FROM pg_class c LEFTJOIN pg_namespace n ON n.oid = c.relnamespace WHERE relkind ='r' AND nspname NOTLIKE'pg_%' AND nspname !='information_schema' ORDERBY pg_total_relation_size(c.oid) DESC;
-- 查找超过1小时的长事务 selectcount(*) from pg_stat_activity where state <>'idle'and (backend_xid isnotnullor backend_xmin isnotnull) and now()-xact_start >interval'3600 sec'::interval;
-- 查看处于等待锁状态 select*from pg_locks wherenot granted; -- 查看等待锁的关系(表,索引,序列等) select*from pg_class where oid=[上面查出来的relation]; -- 查看等待锁的数据库 select*from pg_database where oid=[上面查出来的database]; -- 锁表状态 select oid from pg_class where relname='可能锁表了的表'; -- 查询出结果则被锁 select pid from pg_locks where relation='上面查出的oid';
-- 输出删除全部表的sql \COPY (SELECT'DROP TABLE IF EXISTS "'|| tablename ||'" CASCADE;'from pg_tables WHERE schemaname ='public') TO'/tmp/sql_output.sql';
-- 添加部分索引(满足条件才建立索引), where 和 select 语句的一致 create index [XXX] where [XXX]
-- 查看当前连接事务执行超时时间 show statement_timeout; -- 设置数据库事务执行超时时间为 60 秒 AlTER DATABASE mydatabse SET statement_timeout='60s'; -- 设置用户事务执行超时时间为 5 分钟 ALTER ROLE guest SET statement_timeout='5min';
子查询优化
PG 的子查询实际有两种,分为子连接(Sublink)和子查询(SubQuery),按子句的位置不同,出现在 from 关键字后的是子查询,出现在 where/on 等约束条件中或投影中的子句是子连接。
子查询:select a.* from table_a a, (select a_id from table_b where id=1) b where b.a_id = a.id;
子连接:select * from table_a where id in(select a_id from table_b where id=1);
在简单的子连接查询下,PG 数据库查询优化器一般会将其转化为内连接的方式:select a.* from table_a a, table_b b where a.id=b.a_id and b.id=1;,正常索引没问题情况下这两种方式都能得一样的结果,最终执行的都是索引内连接结果。但在某些情况下,PG 查询优化器在子连接的 SQL 下,子连接的查询会走索引,而主查询会顺序扫描(Seq Scan),原因是当 table_a 的数据量很大时,索引值又有很多重复的,同时查询优化器也不知道子连接返回的具体数据,这时查询优化器可能会认为顺序扫描更快,从而不走索引,导致耗时增加,所以为减少查询优化器的不确定性,最好是直接使用内连接的方式代替 in 语句。 当然,对于特别复杂的查询业务,还是开启事务,分多次查询,在代码层做一些业务逻辑处理更合适,别让数据库把事情全做了,这也能减轻数据库的压力。 PG 查询计划执行路径可以看看: PostgreSQL 查询语句优化,postgresql通过索引优化查询速度操作
-- 创建只读组 create role readonly_group; -- 设置只读模式 ALTER ROLE readonly_group SET default_transaction_read_only TO'on'; -- 创建只读用户继承只读组 createuser reader with password 'reader'in role readonly_group; -- 删除用户 dropuser reader; -- 将只读组权限赋给只读用户 grant readonly_group to reader;
-- 读权限 GRANTSELECTONALL TABLES IN SCHEMA public TO readonly_group; GRANTSELECTONALL SEQUENCES IN SCHEMA public TO readonly_group; GRANTEXECUTEONALL FUNCTIONS IN SCHEMA public TO readonly_group; -- 写权限 GRANTINSERT, UPDATE, DELETEONALL TABLES IN SCHEMA public TO write_group; GRANT USAGE ONALL SEQUENCES IN SCHEMA public TO write_group;
# 主备机不同步时,re_wind恢复结点 wal_log_hints = on # 设置最大流复制数(从库数) max_wal_senders = 3 wal_keep_segments = 64 # 支持从库读,以及从库再拉从库 hot_standby = on
设置主库:pg_hba.conf
1 2 3 4 5 6
# Allow replication connections from localhost, by a user with the # replication privilege. local replication all trust host replication all 127.0.0.1/32 trust host replication all ::1/128 trust host replication all 0.0.0.0/0 md5
psql -d postgresql://owner_user:pswd@host:port/db_name -t -A -F"," -c " SELECT DISTINCT 'ALTER TABLE ' || quote_ident(nsp.nspname) || '.' || quote_ident(cls.relname) || ' ADD CONSTRAINT ' || quote_ident(con.conname) || ' FOREIGN KEY (' || array_to_string(ARRAY( SELECT quote_ident(att.attname) FROM pg_attribute att WHERE att.attnum = ANY(con.conkey) AND att.attrelid = cls.oid), ', ') || ') REFERENCES ' || quote_ident(f_nsp.nspname) || '.' || quote_ident(f_cls.relname) || ' (' || array_to_string(ARRAY( SELECT quote_ident(att.attname) FROM pg_attribute att WHERE att.attnum = ANY(con.confkey) AND att.attrelid = f_cls.oid), ', ') || ') ON DELETE ' || CASE con.confdeltype WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT' WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END || ' ON UPDATE ' || CASE con.confupdtype WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT' WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END || ';' FROM pg_constraint con JOIN pg_class cls ON con.conrelid = cls.oid JOIN pg_namespace nsp ON cls.relnamespace = nsp.oid JOIN pg_class f_cls ON con.confrelid = f_cls.oid JOIN pg_namespace f_nsp ON f_cls.relnamespace = f_nsp.oid WHERE con.contype = 'f';" > db_name_fkeys.sql
pg_dump -d postgresql://user:pswd@host:port/db_name --data-only -F d -j 4 -f ./db_name_data_dir
新建数据库实例
1
pg_ctl init -D ~/new_db_data
导入数据库全局用户/权限
1
psql -U superuser -p port -f db_name_user.sql
新建数据库
1
create database new_db_name owner owner_user
导入数据库全部表结构
1
psql -U superuser -p port -f db_name_schema.sql
移除新库外键约束
1 2 3 4 5 6 7 8 9 10 11 12
psql -d postgresql://owner_user:pswd@host:port/db_name <<EOF DO \$\$ DECLARE r RECORD; BEGIN FOR r IN (SELECT conname, conrelid::regclass FROM pg_constraint WHERE contype = 'f') LOOP EXECUTE 'ALTER TABLE ' || r.conrelid || ' DROP CONSTRAINT ' || r.conname; END LOOP; END \$\$; EOF
proc_name="create index" functionwait_create_idx() { whiletrue; do proc_cnt=`ps aux | grep "$proc_name" | wc -l` if [ $proc_cnt -le 10 ]; then# 10个并发进程 break fi sleep 60 # 休眠60s done }
常见问题:
当自增主键报 duplicate key value violates unique constraint 主键冲突时,一般是因为存在手动分配 id 的数据(复制表或着手动插入分配了 id),自增主键 seqence TABLE_COLUMN_seq 没有更新,新插入一个值自增 id 和数据库已插入的分配 id 冲突,此时需要执行 SELECT setval('TABLE_COLUMN_seq', (SELECT max(COLUMN) FROM "TABLE")) 更新自增主键;