案例说明:

数据库在日常的维护过程中,在执行表查询(select),如下图所示,出现“could not read block 0 in file "base/16385/16408": read only 512 of 8192 bytes”故障,通过对“base/16385/16408”的定位,故障和toast表有关。本案例复现了以上故障,并提供了解决方案。

适用版本:

KingbaseES V8R6

一、案例复现

TOAST存储的表不能单独创建,只有当普通表包含了main,extended或external存储格式的字段时,系统会自动创建一个和普通表关联的TOAST表。当一行记录(tuple)存储的(包括压缩后的大小)大小超过TOAST_TUPLE_THRESHOLD(默认2K)时,会存储到TOAST表。

1、创建测试表及插入数据

# 创建测试表
prod=# create table test1(id int primary key ,v_name varchar);
CREATE TABLE #查看表结构
prod=# \d+ test1
Table "public.test1"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+----------+--------------+-------------
id | integer | | not null | | plain | |
v_name | varchar | | | | extended | |
Indexes:
"test1_pkey" PRIMARY KEY, btree (id)
Access method: heap # 插入大字段数据
prod=# insert into test1 select generate_series(1,100),'a';
INSERT 0 100
prod=# insert into test1 select generate_series(101,200),repeat(md5(random()::text),8000);
INSERT 0 100
prod=# insert into test1 select generate_series(201,300),'b';
INSERT 0 100
---当字段的storage标识为“extended“时,如果字段值默认超过2k,会对字段执行压缩,如果压缩后的size
仍大于2k,则将字段值存入toast表,在源表建立到toast表的指针。

2、查看toast表信息

#获取源表对应的toast表OID
prod=# select oid,reltoastrelid,relname from pg_class where relname='test1';
oid | reltoastrelid | relname
-------+---------------+---------
16405 | 16408 | test1
(1 row) #获取toast表名称
prod=# select oid,relname from pg_class where oid=16408;
oid | relname
-------+----------------
16408 | pg_toast_16405
(1 row) #获取toast表数据文件存储路径
prod=# select pg_relation_filepath('pg_toast.pg_toast_16405');
pg_relation_filepath
----------------------
base/16385/16408
(1 row) prod=# select count(*) from pg_toast.pg_toast_16405;
count
-------
200
(1 row) prod=# \d+ pg_toast.pg_toast_16405;
TOAST table "pg_toast.pg_toast_16405"
Column | Type | Storage
------------+---------+---------
chunk_id | oid | plain
chunk_seq | integer | plain
chunk_data | bytea | plain

二、模拟toast表数据文件故障

#模拟toast表数据文件故障
[kingbase@node102 ~]$ dd if=/dev/zero of=/data/kingbase/v8r6_c6/data/base/16385/16408 bs=512 count=1
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000188319 s, 2.7 MB/s [kingbase@node102 ~]$ ls -lh /data/kingbase/v8r6_c6/data/base/16385/16408
-rw------- 1 kingbase kingbase 512 Nov 3 11:21 /data/kingbase/v8r6_c6/data/base/16385/16408 #重启数据库并清理缓存
[kingbase@node102 bin]$ ./sys_ctl stop -D /data/kingbase/v8r6_c6/data
waiting for server to shut down.... done
server stopped [root@node102 ~]# echo 3 > /proc/sys/vm/drop_caches [kingbase@node102 bin]$ ./sys_ctl start -D /data/kingbase/v8r6_c6/data
waiting for server to start....2022-11-03 11:22:12.466 CST [15429] LOG: sepapower extension initialized
.......
server started #查询源表数据出现块故障
prod=# select * from test1;
ERROR: could not read block 0 in file "base/16385/16408": read only 512 of 8192 bytes # toast表数据为空
prod=# select * from pg_toast.pg_toast_16405 limit 2;
chunk_id | chunk_seq | chunk_data
----------+-----------+------------
(0 rows) # 可以对源表做行统计查询
prod=# select count(*) from test1;
count
-------
300
(1 row)

三、解决toast表故障步骤

1、尝试重建索引并对表分析

# 尝试重建索引
prod=# reindex table test1;
REINDEX
prod=# reindex table pg_toast.pg_toast_16405;
REINDEX # 执行表分析
prod=# vacuum analyze test1;
VACUUM # 源表查询依然出现故障
prod=# select * from test1;
ERROR: missing chunk number 0 for toast value 16413 in pg_toast_16405

2、定位源表发生故障的记录

# 尝试通过手工方式定位
prod=# select * from test1 order by id limit 1 offset 1;
id | v_name
----+--------
2 | a
(1 row) prod=# select * from test1 order by id limit 1 offset 100;
ERROR: missing chunk number 0 for toast value 16413 in pg_toast_16405 prod=# select * from test1 order by id limit 100 offset 0;
id | v_name
-----+--------
1 | a
2 | a
3 | a
4 | a
5 | a
6 | a
7 | a
8 | a
9 | a
........ prod=# select * from test1 order by id limit 100 offset 1;
ERROR: missing chunk number 0 for toast value 16413 in pg_toast_16405 #通过脚本定位故障记录 [kingbase@node102 ~]$ cat chk_toast.sh
#!/bin/bash
CNT=300 #300是表的总行数
CMD_DIR='/opt/Kingbase/ES/V8R6_C6/Server/bin'
PORT=54325 for ((i=1; i<=CNT;i++))
do
$CMD_DIR/ksql -U system prod -p $PORT -c "SELECT * FROM test1 order by id LIMIT 1 offset $i" >/dev/null || echo $i
done # 执行脚本
[kingbase@node102 ~]$ sh chk_toast.sh
ERROR: missing chunk number 0 for toast value 16413 in pg_toast_16405
100
ERROR: missing chunk number 0 for toast value 16414 in pg_toast_16405
101
ERROR: missing chunk number 0 for toast value 16415 in pg_toast_16405
102
........
ERROR: missing chunk number 0 for toast value 16511 in pg_toast_16405
198
ERROR: missing chunk number 0 for toast value 16512 in pg_toast_16405
199 ---如上所示,从第100行开始到199行,字段v_name的字段值存储在toast表,因toast表故障,因此无法从源表访问。

3、清理源表中故障记录

# 确定源表需清理的记录
prod=# select * from test1 order by id limit 1 offset 99;
id | v_name
-----+--------
100 | a
(1 row) prod=# select * from test1 order by id limit 1 offset 199;
ERROR: missing chunk number 0 for toast value 16512 in pg_toast_16405 prod=# select * from test1 order by id limit 1 offset 200;
id | v_name
-----+--------
201 | b
(1 row) #删除源表中故障记录
prod=# delete from test1 where id >100 and id <201;
DELETE 100 #清理故障记录后源表可以正常查询
prod=# select * from test1;
id | v_name
-----+--------
1 | a
2 | a
3 | a
4 | a
5 | a
6 | a
7 | a
8 | a
9 | a
10 | a
11 | a
12 | a
13 | a
14 | a
....... prod=# select count(*) from test1;
count
-------
200
(1 row) prod=# select * from pg_toast.pg_toast_16405;
chunk_id | chunk_seq | chunk_data
----------+-----------+------------
(0 rows) #源表插入数据
prod=# insert into test1 select generate_series(101,200),repeat(md5(random()::text),8000);
INSERT 0 100 #toast表生成新的记录
prod=# select count(*) from pg_toast.pg_toast_16405;
count
-------
200
(1 row) prod=# insert into test1 select generate_series(301,400),repeat(md5(random()::text),8000);
INSERT 0 100
prod=# select count(*) from pg_toast.pg_toast_16405;
count
-------
400
(1 row) prod=# select count(distinct chunk_id) from pg_toast.pg_toast_16405 ;
count
-------
200
(1 row) ---从以上所示,toast表故障问题已经解决。

四、总结

因toast表坏块问题,将导致源表不可访问,如果有有效的备份,可以通过备份来进行故障的恢复;如果没有有效的备份,可以通过对源表故障记录的清理,完成toast表的恢复。

KingbaseES V8R6运维案例之---普通表toast表故障修复的更多相关文章

  1. KingbaseES V8R6备份恢复案例之---自定义表空间指定恢复目录数据恢复

    案例说明: KingbaseES V8R6在通过sys_rman执行物理备份恢复时,可以通过参数'--kb1-path',指定恢复的数据(data)目录,但如果原备份中包含自定义表空间时,需要建立表空 ...

  2. KingbaseES V8R3集群运维案例之---用户自定义表空间管理

    ​案例说明: KingbaseES 数据库支持用户自定义表空间的创建,并建议表空间的文件存储路径配置到数据库的data目录之外.本案例复现了,当用户自定义表空间存储路径配置到data下时,出现的故障问 ...

  3. KingbaseES V8R6集群管理运维案例之---repmgr standby switchover故障

    案例说明: 在KingbaseES V8R6集群备库执行"repmgr standby switchover"时,切换失败,并且在执行过程中,伴随着"repmr stan ...

  4. KingbaseES V8R6集群运维案例之---repmgr standby promote应用案例

    案例说明: 在容灾环境中,跨区域部署的异地备节点不会自主提升为主节点,在主节点发生故障或者人为需要切换时需要手动执行切换操作.若主节点已经失效,希望将异地备机提升为主节点. $bin/repmgr s ...

  5. 运维案例 | Exchange2010数据库损坏的紧急修复思路

    ​​关注嘉为科技,获取运维新知 Exchange后端数据库故障,一般都会是比较严重的紧急故障,因为这会直接影响到大面积用户的正常使用,而且涉及到用户数据.一旦遇到这种级别的故障,管理员往往都是在非常紧 ...

  6. KingbaseES V8R6备份恢复案例之---同一数据库创建不同stanza备份

    案例说明: 在生产环境,有的应用需要调用数据库的sys_rman做备份,为了区分数据库自身的sys_rman备份和应用的备份,可以使用不同的stanza name创建备份.本案例介绍了,如何在King ...

  7. KingbaseES V8R6备份恢复案例之--删除test数据库后sys_backup.sh备份

    案例说明: KingbaseES V8R6通过sys_backup.sh执行物理备份,默认sys_backup.sh执行备份初始化时,需要连接test数据库进行身份的认证:在一些生产环境为了安全需求, ...

  8. KingbaseES V8R6备份恢复案例之---手工清理冗余历史备份

    案例说明: 对于KingbaseES V8R6的通过sys_rman执行的物理历史备份,可以在执行备份时,备份的保留(retention)策略自动清理.不能通过手工删除备份,可以通过expire参数手 ...

  9. python运维开发(十九)----Django后台表单验证、session、cookie、model操作

    内容目录: Django后台表单验证 CSRF加密传输 session.cookie model数据库操作 Django后台Form表单验证 Django中Form一般有2种功能: 1.用于做用户提交 ...

  10. KingbaseES V8R3集群运维案例之---主库系统down failover切换过程分析

    ​ 案例说明: KingbaseES V8R3集群failover时两个cluster都会触发,但只有一个cluster会调用脚本去执行真正的切换流程,另一个有对应的打印,但不会调用脚本,只是走相关的 ...

随机推荐

  1. golang指针和结构体

    指针 指针操作 指针包括指针地址.指针类型和指针取值 &: &符号放在变量前面进行取地址操作 **:*放在变量前面根据地址进行取值 指针地址: func main() { var a ...

  2. 3分钟总览微软TPL并行编程库

    有小伙伴问我每天忽悠的TPL是什么?☹️ 这次站位高一点,严肃讲一讲. 引言 俗话说,不想开飞机的程序员不是一名好爸爸:作为微软技术栈的老鸟,一直将代码整洁之道奉为经典, 优秀的程序员将优雅.高性能的 ...

  3. 【Android 逆向】【攻防世界】app1

    1. apk安装到手机, 老套路了 2. jadx打开 this.btn.setOnClickListener(new View.OnClickListener() { // from class: ...

  4. [BUUCTF][Web][极客大挑战 2019]EasySQL 1

    打开靶机对应的url 界面显示需要输入账号和密码 分别在两个输入框尝试加单引号尝试是否有sql注入的可能,比如 123' 发现两个框可以注入,因为报了个错误信息 You have an error i ...

  5. 一秒出图?SDXL-Turbo实时AI绘画整合包下载

    SDXL Turbo是一种快速生成的AI构图模型,它基于一种称为对抗性扩散蒸馏的新训练方法,该方法允许在1到4个步骤中以高图像质量对大规模基础图像扩散模型进行采样,并将其与对抗性损失相结合,以确保即使 ...

  6. Vue3学习(十八) - TreeSelect 树选择

    写在前面 本以为可以在家学习一天,结果家里来了客人拜年,就没学习上,有点小遗憾吧. 昨天完成从分类管理的前后端代码复制出文档管理的前后端代码,遗留问题是只能选择一级父分类.值得说的是,昨晚的遗留的问题 ...

  7. python运算符---day04

    1.python运算符 (1)算数运算符: + - * / // % ** (2)比较运算符: > < >= <= == != (3)赋值运算符:= += -= *= /= / ...

  8. 异常处理之raise A from B

    raise A from B 语句用于连锁chain异常 from 后面的B可以是: - 异常类 - 异常实例 - None 如果B是异常类或者异常实例,那么B会被设置为A的__cause__属性,表 ...

  9. 【LeetCode动态规划#15】最长公共子序列II

    最长公共子序列(二) 描述 给定两个字符串str1和str2,输出两个字符串的最长公共子序列.如果最长公共子序列为空,则返回"-1".目前给出的数据,仅仅会存在一个最长的公共子序列 ...

  10. 【LeetCode哈希表#1】有效的字母异位词+赎金信(数组)

    有效的字母异位词 力扣题目链接(opens new window) 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词. 示例 1: 输入: s = "anagr ...