原文链接: https://blog.youkuaiyun.com/qq_25938327/article/details/125111477
异常信息
could not read block 1971 in file \"base/16413/35496215\": read only 4992 of 8192 bytes
分析
以上日志表示数据表文件损坏。这通常是由于异常断电或误操作导致的。这里“16413”是发生问题的数据库的对象id(oid), “35496215”表示发生问题的表的文件结点(filenode)
如果发生损坏的表以及损坏的页面数量较少,我们可以以牺牲部分数据的代价恢复整体;如果损坏的表数量过多,或者损失的数据非常重要,就需要从备份中恢复数据了。
当发生损坏的表以及损坏的页面数量较少时,解决方法如下:
1.确定发生问题的数据库。连接任意数据库,执行下面的sql语句:
select datname from pg_database where oid = 16413;
查询结果:testdb
这表示发生问题的数据库名是testdb
2.查找损坏的数据库对象。连接发生问题的数据库,执行下面的sql语句:
select relname,relkind from pg_class where relfilenode = 35496215
如果查询结果中 relkind = r,表示损坏的是表。
例如:tb_test, r
relname = tb_test这表示损坏的表是tb_test。
如果查询结果中relkind = i,表示损坏的是一个索引。
例如:tb_test_index, i
或者:tb_test_pkey, i
需要注意,损坏的可能是普通索引,也可能是主键或唯一键。如果索引的名称中有"_pkey"等很可能属于主键,而名称中含有 "_key"则很可能属于唯一键。
还需要格外注意一点,表/索引可修复的前提条件是损坏的表是应用程序创建的表/索引,而不是PostgreSQL的系统表和建立在其上的索引。如果系统表/建立在其上的索引发生损坏,则需要从备份中恢复数据库。判断一个表是否是系统表,最简单的方法是:如果表名是“pg_”开头的,则说明它是系统表。
pgclass.relkind 的值有下面几种:
r表示ordinary table(普通表)
i表示index(索引)
s表示sequence(序列)
v表示view(视图)
m表示materialized view(物化视图)
c表示composite type(复合类型)
t表示TOAST table(TOAST 表)
f表示foreign table(外部表)
3. 修复损坏的数据库对象。连接发生损坏的数据库,执行修复命令。
如果损坏的是表,以tb_test为例,则依次执行下列命令即可完成修复:
set zero_damaged_pages = on;
vacuum tb_door;
reindex table tb_test;
如果损坏的是普通索引,以tb_test_index为例, 则依次执行:
set zero_damaged_pages = on;
reindex index tb_test_index;
如果损坏的是主键或唯一键,则首先需要找到它所在的表,以tb_test_pkey为例:
select tablename,indexname from pg_indexes where indexname = "tb_test_pkey";
查询结果:tb_test, tb_test_pkey
然后获取索引的定义:
select pg_get_constraintdef((select oid from pg_constraint where conname = "tb_test_pkey"));
查询结果:PRIMARY KEY (id)
然后重新创建这个约束:
alter table tb_test drop constraint tb_test_pkey;
alter table tb_test add constraint tb_test_pkey PRIMARY KEY (id);