微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

PostgreSQL change unlogged table to logged table

说明:该文章转自 http://blog.163.com/digoal@126/blog/static/16387704020133274380469/ 的一位pg数据库大牛


今天一位网友给我留言能不能将unlogged table 改成normal table,也就是logged table.

答案是可以的.
unlogged table的变更不记录pg_xlog,所以这点在流复制环境或者log shipping 复制环境会遇到小小的麻烦,但是不要紧,这个是可以解决的.
以下是修改过程 :
主库,创建unlogged table :
  
  
digoal=> create unlogged table t(id int);
CREATE TABLE
digoal=> insert into t values (1);
INSERT 0 1
digoal=> select * from pg_class where relname='t';
relname | relnamespace | reltype | reloftype | relowner | relam | relfilenode | reltablespace | relpages | reltuples | relal
lvisible | reltoastrelid | reltoastidxid | relhasindex | relisshared | relpersistence | relkind | relnatts | relchecks | relh
asoids | relhaspkey | relhasrules | relhastriggers | relhassubclass | relfrozenxid | relacl | reloptions
---------+--------------+---------+-----------+----------+-------+-------------+---------------+----------+-----------+------
---------+---------------+---------------+-------------+-------------+----------------+---------+----------+-----------+-----
-------+------------+-------------+----------------+----------------+--------------+--------+------------
t | 2200 | 154316 | 0 | 24602 | 0 | 154314 | 0 | 0 | 0 |
0 | 0 | 0 | f | f | u | r | 1 | 0 | f
| f | f | f | f | 32079149 | |
(1 row)
注意 relpersistence=u,也就是unlogged的意思.
此时去standby节点查询,有t表,但是查询数据会报错.
  
  
digoal => \dt
List of relations
Schema | Name | Type | Owner
--------+--------------+-------+------------
public | t | table | digoal
( 2 rows )
digoal=> select * from t;
ERROR: cannot access temporary or unlogged relations during recovery
在主库将t表改成logged的. 使用超级用户
  
  
digoal=> \cdigoalpostgres
You are Now connected to database "postgres" as user "postgres".
digoal=# update pg_class set relpersistence='p' where relname='t';
UPDATE 1
此时去standby查询t表报错变了,原因是unlogged表的dml操作不会写pg_xlog,因此数据块不会复制到standby节点.
  
  
digoal=> select * from t;
ERROR: Could not open file "base/12788/154314": No such file or directory
此时在主节点插入一条记录
  
  
digoal=# insert into t values (1);
INSERT 0 1
再到standby节点查询
  
  
digoal=> select * from t;
id
----
1
1
(2 rows)
正常了,这又是为什么呢,因为t表已经改成logged了,pg_xlog会记录,所以数据块被复制到standby节点了.

但是再来看一个测试 .
   
   
digoal=# drop table t;
DROP TABLE
digoal=# create unlogged table t(id int);
CREATE TABLE
digoal=# insert into t select generate_series(1,1000);
INSERT 0 1000
digoal=# select min(ctid),max(ctid) from t;
min | max
-------+--------
(0,1) | (4,96)
(1 row)
-- 注意现在t表有5个数据块. 而不是1个数据块.
   
   
digoal=# update pg_class set relpersistence='p' where relname='t';
UPDATE 1
digoal=# insert into t select generate_series(1,1000);
INSERT 0 1000
digoal=# select count(*) from t;
count
-------
2000
(1 row)
digoal=# select min(ctid),max(ctid) from t;
min | max
-------+---------
(0,1) | (8,192)
(1 row)
在standby节点看看数据是否都复制过来了呢?
  
  
digoal=> \c postgres postgres
You are Now connected to database "postgres" as user "postgres".
digoal=# select count(*) from t;
count
-------
1096
(1 row)
digoal=# select min(ctid),max(ctid) from t;
min | max
-------+---------
(4,192)
(1 row)
注意是从4号数据块开始复制过来的. 原因是t表变成logged后的DML操作只影响到了4号数据块,并且新建了几个数据块,老的数据块没有改变,所以不会记入pg_xlog,因此复制也只复制了4号数据块开始的新数据块.
遇到这个问题怎么处理呢?
方法1 :
如果表比较小,vacuum full就可以了,因为vacuum full会重建表. pg_xlog也会重新生成.
主库执行 :
  
  
digoal=# vacuum full t;
VACUUM
digoal=# select count(*) from t;
count
-------
2000
(1 row)
standby库验证 :
  
  
digoal=# select min(ctid),max(ctid) from t;
min | max
-------+---------
(0,192)
(1 row)
digoal=# select count(*) from t;
count
-------
2000
(1 row)

方法2 :
如果表很大了,例如超过了1个数据文件时. 那么可以冻结t表的dml操作,直接复制未在standby创建的的数据文件. 以及覆盖不完整的数据文件.
  
  
digoal=# select pg_relation_filepath('t'::regclass);
pg_relation_filepath
----------------------
base/12788/154322
(1 row)
把这个文件以及 base/12788/154322.* 复制到standby即可.
复制完后解冻.

[其他注意事项]
1. 如果unlogged表涉及到索引,索引也需要修改.
 
 
digoal=# create unlogged table t(id int primary key,info text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t_pkey" for table "t"
CREATE TABLE
digoal=# select relpersistence from pg_class where oid='t'::regclass;
relpersistence
----------------
u
(1 row)
digoal=# select relpersistence from pg_class where oid='t_pkey'::regclass;
relpersistence
----------------
u
(1 row)
digoal=# update pg_class set relpersistence='p' where oid='t'::regclass;
UPDATE 1
digoal=# update pg_class set relpersistence='p' where oid='t_pkey'::regclass;
UPDATE 1

原文地址:https://www.jb51.cc/postgresql/195232.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐