POSTGRESQL 修改字段由大到小 为什么会 rewrite table

2021-01-14 00:00:00 数据 字段 都是 导致 长度

近有一位同学问关于修改字段为什么改大不 rewrite table 但是改小字段长度就会导致rewrite table , 其实这就是POSTGRESQL 在修改字段上面有一个问题,这就是人尽皆知的rewrite,rewrite本身并没有什么错误的,但是如果在线进行大表的操作者就会引起表锁,导致业务中断。那问题来了,为什么会修改表的结构对于varchar从大到小,或者数据类型变化会导致rewrite table


上面这张图大家都熟悉,就是PG的页面的图形,从上图看一个页面中下面是保存的行的数据,上面是item 是存储空间分配的指针,这一行数据从哪里到哪里,头尾相接的一种数据结构。之前老版本的PG无论是将字段由小改大还是反过来都是导致表的rewrite.


那么我们需要验证PG 为什么在新版本中对于扩展不在进行重写而对于收缩还是会导致收缩。


我们通过逻辑分析来考虑


1  通过 item指针来进行行的分割的话,那么增加一个行的长度并没有触犯item的底线,因为之前的一行里面的字段长度是固定的也就是可以预分配这个空间,而如果我将varchar(30) 改变为 varchar(40) 则原有的行都不需要变动,疑问都符合varchar(40)以内,所以只有后续的行的数据会进行会进行扩展,那就不会导致存储空间的溢出。所以以小改大都是可以的。



  • Field Type Length Offset Description

  • t_xmin TransactionId 4 bytes 0 insert XID stamp

  • t_xmax TransactionId 4 bytes 4 delete XID stamp

  • t_cid CommandId 4 bytes 8 insert and/or delete CID stamp (overlays with t_xvac)

  • t_xvac TransactionId 4 bytes 8 XID for VACUUM operation moving a row version

  • t_ctid ItemPointerData 6 bytes 12 current TID of this or newer row version

  • t_infomask2 uint16 2 bytes 18 number of attributes, plus various flag bits

  • t_infomask uint16 2 bytes 20 various flag bits

  • t_hoff uint8 1 byte 22 offset to user data



上图是一个表的信息,我看可以看到t_hoff 是存储用户数据的地方,


详情请从以下网址查看

https://www.programmersought.com/article/7081994849/


2  如果是缩小字段会引起数据长度的变化和收缩,则会这样的情况下就需要重新写表,至少对先前定义的内容以及界限进行重新组织。


这点可以在 tiemid.h找到一些线索

https://doxygen.postgresql.org/structItemIdData.html

其中 itemid.h 其中包含了lp_off lp_flags  lp_len 等几个data fields


https://medium.com/@djboris/postgresql-physical-storage-of-rows-da20a1389509

其中个图片对上面hexdump 中的HEX:18 进行了描述。


以上是我对这位同学的,浅薄的回复,因为近的确是没有什么时间,不过我可以肯定的一句,如果将脑子钻研到技术中,很多烦恼都会暂时离开。


相关文章