场景:客户反应有时查询业务表报读取数据块错误
“ERROR: could not read block xxx in file”
第一时间想到查询数据库的日志
后台日志能看到报错文件的filenode且发现是在取读取具体的数据块报错,当然还有相应的SQL语句,这里列报错文件
ERROR: could not read block 27417 in file “base/13642/32145.2”
上面的信息还不能确认是表块损坏还是索引块损坏
根据filenode查看报错对象的名称
select * from pg_class where relfilenode=’’
这里查询出来的结果,怎么确认是表对象,还是索引对象呢?
select schemaname,tablename,indexname from pg_indexes where tablename=’’ or indexname =’’
上面还是不能确认的话,可以通过pg_dump导出数据,因为pg_dump不使用索引,直接从表中获取数据
验证故障现象
通过全表访问数据
set enable_indexscan =‘off’;
explain analzye select * from 表对象
通过索引访问数据
explain analzye select * from 表对象
解决方法
确认是索引块损坏后,可以重建索引,索引重建有几种方式
1、rebuild index --该方式会锁表,DML和select都会被锁,需要根据实际业务申请维护时间
2、rebuild index concurrently --postgresl12才的功能
3、create index concurrently --并发创建索引,会使表的插入更新操作变慢,但不会锁表。
建议
采用第3种方式,先创建一个新索引,再删除有问题的索引。
总结:
1、通过pg_dump验证到底是索引块还是表块损坏
2、rebuild index会锁表,DML和select都会被锁,生产环境需要特别小心
思考:
如果是表块损坏,没有备份,怎么解决了呢,访问时是否能跳过该数据块呢?
webdata=# select * from pg_settings where name like ‘%zero%’;
name | zero_damaged_pages
setting | off
unit |
category | Developer Options
short_desc | Continues processing past damaged page headers.
extra_desc | Detection of a damaged page header normally causes PostgreSQL to report an error, aborting the current transaction. Setting zero_damaged_pages to true causes the system to instead report a warning, zero out the damaged page, and continue processing. This behavior will destroy data, namely all the rows on the damaged page.
context | superuser
vartype | bool
source | default
min_val |
max_val |
enumvals |
boot_val | off
reset_val | off
sourcefile |
sourceline |
pending_restart | f
有效备份的重要性