PG常见错误集合
来源:互联网 发布:网络诈骗案一般关多久 编辑:程序博客网 时间:2024/05/25 21:34
missing chunk number x for toast value x in pg_toast_x
相关知识
- toast是The OverSized Attribute Storage Technique(超尺寸字段存储技术)的缩写,是超长字段在pg中的一种存储方式。
- pg采用的存储默认是每个页面存储固定8Kb大小的数据,并且元组(行记录)不允许跨页面存储,所以并不能直接存储大字段数据。
- 所以toast会将大字段值压缩或者分散为多个物理行来存储。
- pg的部分类型数据支持toast,因为不是所有字段都会产生大字段数据的,完全没必要用到Toast技术(比如date,time,boolean等)。
- 支持Toast的数据类型应当时变长的(variable-length)。
- 当表中字段任何一个有Toast,那这个表都会有这一个相关联的Toast表。
- OID被存储在pg_class.reltoastrelid里面。
- 超出的数值将会被分割成chunks,并最多toast_max_chunk_size 个byte(缺省是2Kb),
- 当存储的行数据超过toast_tuple_threshold值(通常是2kB),就会触发toast存储,这时toast将会压缩或者移动字段值直到超出部分比toast_tuple_targer值小(这个值通常也是2KB)。
相比较普通表(MAIN TABLE),TOAST有额外的三个字段
chunk_id:标识TOAST表的OID字段
chunk_seq:chunk的序列号,与chunk_id的组合唯一索引可以加速访问
chunk_data:存储TOAST表的实际数据toast有4种存储策略:
PLAIN:避免压缩和行外存储。只有那些不需要TOAST策略就能存放的数据类型允许选择(例如int类型),而对于text这类要求存储长度超过页大小的类型,是不允许采用此策略的
EXTENDED:允许压缩和行外存储。一般会先压缩,如果还是太大,就会行外存储
EXTERNA:允许行外存储,但不许压缩。类似字符串这种会对数据的一部分进行操作的字段,采用此策略可能获得更高的性能,因为不需要读取出整行数据再解压。
MAIN:允许压缩,但不许行外存储。不过实际上,为了保证过大数据的存储,行外存储在其它方式(例如压缩)都无法满足需求的情况下,作为最后手段还是会被启动。因此理解为:尽量不使用行外存储更贴切。
举例说明
创建表
postgres=# create table blog(id int, title text, content text);CREATE TABLEpostgres=# \d+ blog; Table "public.blog" Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- id | integer | | plain | | title | text | | extended | | content | text | | extended | |
可以看到,interger默认TOAST策略为plain,而text为extended。PG资料告诉我们,如果表中有字段需要TOAST,那么系统会自动创建一张TOAST表负责行外存储,那么这张表在哪里?
postgres=# select relname,relfilenode,reltoastrelid from pg_class where relname='blog'; relname | relfilenode | reltoastrelid ---------+-------------+--------------- blog | 16441 | 16444(1 row)
通过上诉语句,我们查到blog表的oid为16441,其对应TOAST表的oid为16444(关于oid和pg_class的概念,请参考PG官方文档),那么其对应TOAST表名则为:pg_toast.pg_toast_16441(注意这里是blog表的oid),我们看下其定义:
postgres=# \d+ pg_toast.pg_toast_16441;TOAST table "pg_toast.pg_toast_16441" Column | Type | Storage ------------+---------+--------- chunk_id | oid | plain chunk_seq | integer | plain chunk_data | bytea | plain
TOAST表有3个字段:
- chunk_id:用来表示特定TOAST值的OID,可以理解为具有同样chunk_id值的所有行组成原表(这里的blog)的TOAST字段的一行数据
- chunk_seq:用来表示该行数据在整个数据中的位置
- chunk_data:实际存储的数据。
现在我们来实际验证下:
postgres=# insert into blog values(1, 'title', '0123456789');INSERT 0 1postgres=# select * from blog; id | title | content ----+-------+------------ 1 | title | 0123456789(1 row)
postgres=# select * from pg_toast.pg_toast_16441; chunk_id | chunk_seq | chunk_data ----------+-----------+------------(0 rows)
可以看到因为content只有10个字符,所以没有压缩,也没有行外存储。然后我们使用如下SQL语句增加content的长度,每次增长1倍,同时观察content的长度,看看会发生什么情况?
postgres=# update blog set content=content||content where id=1;UPDATE 1postgres=# select id,title,length(content) from blog; id | title | length ----+-------+-------- 1 | title | 20(1 row)
postgres=# select * from pg_toast.pg_toast_16441; chunk_id | chunk_seq | chunk_data ----------+-----------+------------(0 rows)
反复执行如上过程,直到pg_toast_16441表中有数据:
postgres=# select id,title,length(content) from blog; id | title | length ----+-------+-------- 1 | title | 327680(1 row)
postgres=# select chunk_id,chunk_seq,length(chunk_data) from pg_toast.pg_toast_16441; chunk_id | chunk_seq | length ----------+-----------+-------- 16439 | 0 | 1996 16439 | 1 | 1773(2 rows)
可以看到,直到content的长度为327680时(已远远超过页大小8K),对应TOAST表中才有了2行数据,且长度都是略小于2K,这是因为extended策略下,先启用了压缩,然后才使用行外存储
下面我们将content的TOAST策略改为EXTERNA,以禁止压缩。
postgres=# alter table blog alter content set storage external;ALTER TABLE
postgres=# \d+ blog; Table "public.blog" Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- id | integer | | plain | | title | text | | extended | | content | text | | external | |
然后我们再插入一条数据:
postgres=# insert into blog values(2, 'title', '0123456789');INSERT 0 1postgres=# select id,title,length(content) from blog; id | title | length ----+-------+-------- 1 | title | 327680 2 | title | 10(2 rows)
然后重复以上步骤,直到TOAST表中产生新的行:
postgres=# update blog set content=content||content where id=2;UPDATE 1postgres=# select id,title,length(content) from blog; id | title | length ----+-------+-------- 2 | title | 2560 1 | title | 327680(2 rows)
postgres=# select chunk_id,chunk_seq,length(chunk_data) from pg_toast.pg_toast_16441; chunk_id | chunk_seq | length ----------+-----------+-------- 16447 | 0 | 1996 16447 | 1 | 1773 16448 | 0 | 1996 16448 | 1 | 564(4 rows)
这次我们看到当content长度达到2560(按照官方文档,应该是超过2KB左右),TOAST表中产生了新的2条chunk_id为16448的行,且2行数据的chunk_data的长度之和正好等于2560。
toast的优缺点
1.可以存储超长超大字段,避免之前不能直接存储的限制
2.物理上与普通表是分离的,检索查询时不检索到该字段会极大地加快速度
3.更新普通表时,该表的Toast数据没有被更新时,不用去更新Toast表toast的劣势:
1.对大字段的索引创建是一个问题,有可能会失败,其实通常也不建议在大字段上创建,全文检索倒是一个解决方案。
2.大字段的更新会有点慢,其它DB也存在,通病
报错原因
某张表关联的toast表的data发生损坏。
解决方法
1、 定位是哪张表的toast有问题:
select 2619::regclass; pg_statistic
2、 找到哪个表有问题后,先对该表做一下简单的修复:
REINDEX table pg_toast.pg_toast_2619;REINDEX table pg_statistic;VACUUM ANALYZE pg_statistic;
3、 定位该表中损坏的数据行。执行
DO $$declare v_rec record;BEGINfor v_rec in SELECT * FROM pg_statistic loop raise notice 'Parameter is: %', v_rec.ctid;raise notice 'Parameter is: %', v_rec;end loop; END;$$ LANGUAGE plpgsql;
4、 将第3步中定位的记录删除:
delete from pg_statistic where ctid ='(50,3)';
5、 重复执行第3,4步,直到全部有问题的记录被清除。
6、 至此,toast问题就解决完了,解决之后,对数据库进行一次完整的维护或者索引重建。
invalid page header in block x of relation base/x/x
相关知识
- 参数zero_damaged_pages是bool型的。
- 默认是off,意思是系统遇到这类因磁盘、内存等硬件引起的问题就会给出这样一份错误提示。
- 当设置为on时,就可以忽略这些错误报告,并擦除掉这些损坏的数据,没受影响的数据还是正常的。
报错原因
系统检测到磁盘页损坏,并导致postgresql数据取消当前的事务并提交一份错误报告信息。
解决方法
1、 关闭数据库服务器。2、 编辑postgresql.conf文件,最后一行加入:zero_damaged_pages = on。保存文件,退出。3、 启动数据库服务器,确认数据库服务是否恢复运行。4、 关闭数据库服务器。5、 编辑postgresql.conf文件,去掉最后一行zero_damaged_pages = on。保存文件,退出。6、 重启数据库。
missing chunk number x for toast value x in pg_toast_x
相关知识
Pg的事务是依靠多版本控制实现的,即一条记录更改前及更改后其实是两条数据,并且都存储在当前表里。这两条记录除了本身的逻辑信息之外,还存有相关事务信息。这些事务信息随着事务的改变而改变。当数据库当前事务id和某一条记录的事务id匹配时,那么这条匹配的记录就会显示。所以,当事务非正常结束时,可能会使某一条记录的事务信息没有更新正确,那么此时我们看到的就可能是两条相同主键的数据。实际上,这是一条数据的两种不同状态。这时就出现了上面的错误。
postgresql 多版本并发控制(MCC)
Postgres用多版本并发控制方式管理事务(Multiversion concurrency control),这点上与Oracle非常相似,后者也采用多版本并发控制机制。
MCC的特点:(通俗点儿)
读不产生独占锁,可以共享,不影响其他事务的读写;
写产生独占锁,数据可以共享,不影响读,但不能同时写;
MCC的目的就是最大化实现并发对数据的访问,postgresql与oracle实现的效果相同,只是方式不同。实质是对事务修改数据的管理方式采用不同方式。
postgresql将修改前后的数据都存储在相同的结构中(新旧版本都存在表中)。两个事务同时访问记录时,通过参考tmin和tmax的标记判断记录的版本,根据版本号与自己当前的事务标识比较,确定自己的数据权限。当事务发生修改或者删除记录后,空间没有立即释放,实质并没有在原来的存储位置上进行更新,而是使用了新的存储空间。系统通过周期性的运行vaccum进程来回收之前的存储空间(与Java虚拟机的垃圾回收机制有点象)。事务提交前,只需要访问原来的数据即可;提交后,系统更新元组的存储标识,直到vaccum进程收回为止。
oracle也是根据事务标识的比较确认数据访问权限。当事务发生修改或者删除记录,oracle将原数据存储在undo段中,事务提交后直接更新相应记录的存储位置,并没有直接使用新的存储空间。oracle的undo段同样用于数据库的介质恢复,在应用完redo日志后(前滚),通过应用undo段中的事务,对数据库进行回滚。
oracle在10g中引入的flashback功能中的flashback drop功能与postgresql的方式就有点类似,只是针对表进行删除标记,并没有释放表所占用的空间,通过对表进行改名。在数据库管理员进行recyclebin操作后,才能释放表所占空间。
postgresql尽管是分配新的空间,对空间的分配很快。在postgresql中也有相应的参数对其进行限制,当更新的数据达到一定的程度时将会直接出发vacuum进行,直接释放掉原来的空间。postgresql与oracle对delete操作产生的空间使用,基本相同。对update操作产生的空间使用不同,相对oracle来说,postgresql可能会产生更多的行迁移或迁移的,这样对性能影响应该是存在的。
报错原因
主键重复,导致重建索引报错。
解决方法
1、 根据报错信息定位问题记录。2、 将问题记录拷贝出,并判断正确状态的数据行。3、 将正确的记录拷贝会表里。4、 对数据库重建索引。
- PG常见错误集合
- mysql 常见错误集合
- Extjs4---常见错误集合
- 常见错误集合
- Extjs4---常见错误集合
- python常见错误集合
- python常见错误集合
- Extjs4常见错误集合
- python常见错误集合
- ceph - pg 常见状态
- VC常见错误大集合
- oracle常见的错误集合
- Android常见莫名错误集合
- android 常见错误集合查询
- jsp常见错误大集合
- Windows常见错误处理--集合
- 常见调试错误操作集合
- pg学习_集合操作
- 利用File获取磁盘信息
- MySQL安装教程
- tomcat8 启动慢问题
- 在使用Mac终端的时候出现Permission denied的问题
- [SYZOI Round1]滑稽♂树
- PG常见错误集合
- Kotlin 实现按钮点击跳转监听事件
- 同页与不同页电气连接
- 关于matlab中princomp的使用说明讲解
- 实现高性能纠删码引擎 | 纠删码技术详解(下)
- android图片内存优化
- Java 模拟浏览器下载
- Android短信验证码自动填写功能的实现
- js如何判断一个对象为空