PostgreSQL text类型短数据存储说明

今天在查看数据库数据文件时,进行一下操作:

CREATE TABLE test ( id int, info text );

INSERT INTO test VALUES (1, ‘abc’), (2, ‘def’);

然后通过hexdump查看数据:

0000000 0000 0000 0140 016f 0000 0000 0020 1fc0
0000010 2000 2004 0000 0000 9fe0 0040 9fc0 0040
0000020 0000 0000 0000 0000 0000 0000 0000 0000
*
0001fc0 023f 0000 0000 0000 0000 0000 0000 0000
0001fd0 0002 0002 0802 0018 0002 0000 6409 6665
0001fe0 023f 0000 0000 0000 0000 0000 0000 0000
0001ff0 0001 0002 0802 0018 0001 0000 6109 6362
0002000

发现text类型中的abc和def在数据文件表示为 09616263和09646566,查看代码可知text类型其实为varlena,他的结构为:

struct varlena
{
	char		vl_len_[4];		/* Do not touch this field directly! */
	char		vl_dat[1];
};

前四个字节为长度标识,在这里只有一个字节,而且3个字符的长度为9,百思不得其解啊,遂进行调查,发现,这是因为插入数据较短,数据库给优化了,将原来长度为4个字节的标识为变成了1个:

else if (VARLENA_ATT_IS_PACKABLE(att[i]) &&
      VARATT_CAN_MAKE_SHORT(val))
 {
    /* convert to short varlena -- no alignment */
    data_length = VARATT_CONVERTED_SHORT_SIZE(val);
                    
    SET_VARSIZE_SHORT(data, data_length);
    memcpy(data + 1, VARDATA(val), data_length - 1);
}

这里主要是由于SET_VARSIZE_SHORT起的作用:

#define SET_VARSIZE_SHORT(PTR, len)                     SET_VARSIZE_1B(PTR, len)

#ifdef WORDS_BIGENDIAN

#define SET_VARSIZE_1B(PTR,len) \
        (((varattrib_1b *) (PTR))->va_header = (len) | 0x80)

#else

#define SET_VARSIZE_1B(PTR,len) \
        (((varattrib_1b *) (PTR))->va_header = (((uint8) (len)) << 1) | 0x01)

so, 考虑到‘\0’占位情况,即3+1=4,4 << 1 = 8, 8 | 0x01 = 9,于是这里便是9。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券