PostgreSQL内存对齐理论是否存在偏差?实验结果存疑求解
PostgreSQL内存对齐实验:理论与实际差值不符的原因
我阅读了一篇关于PostgreSQL内存对齐的文章,结合文章示例及自身经验做了如下实验:
CREATE TABLE tab ( col1 smallint, col2 timestamp, col3 integer, col4 double precision ); CREATE TABLE tab2 ( col2 timestamp, col4 double precision, col3 integer, col1 smallint ); INSERT INTO tab (col1, col2, col3, col4) SELECT (random()*32767)::smallint, NOW() - (random()*365)::int * INTERVAL '1 day' + (random()*86400)::int * INTERVAL '1 second', (random()*1000)::int, random()*100.0 FROM generate_series(1,10000); INSERT INTO tab2 (col2, col4, col3, col1) SELECT NOW() - (random()*365)::int * INTERVAL '1 day' + (random()*86400)::int * INTERVAL '1 second', random()*100.0, (random()*1000)::int, (random()*32767)::smallint FROM generate_series(1,10000);
查询表大小后,tab表返回606208字节,tab2表返回524288字节,实际差值为81920字节;但按理论计算应为10 padding bytes * 10000 rows = 100000字节,理论结果与实验不符,请问遗漏了什么?
核心原因:两个关键存储细节被忽略
1. 元组总长度的8字节对齐要求
PostgreSQL要求每个元组的**总长度(元组头部+用户数据)**必须是8字节的倍数,这修正了你的padding计算:
- tab表:
用户数据部分:smallint(2)需要6字节padding以对齐timestamp的8字节边界,随后integer(4)需要4字节padding以对齐double precision的8字节边界,最终用户数据段总长度为2+6+8+4+4+8=32字节。加上固定的24字节元组头部(已对齐),单条元组总长度为24+32=56字节(8的倍数)。 - tab2表:
用户数据部分:timestamp(8)+double(8)+integer(4)+smallint(2)=22字节,需额外2字节padding使总用户数据长度达到24字节(满足8字节对齐)。加上24字节头部,单条元组总长度为24+24=48字节(8的倍数)。
单条元组的实际padding差值为(6+4)-2=8字节,10000行的理论差值应为8*10000=80000字节,而非你最初计算的100000字节。
2. 磁盘块的块级对齐统计
PostgreSQL默认以8KB(8192字节)为磁盘块大小,表大小统计会按完整磁盘块计算,即使最后一个块未被填满:
- 10000行数据在两个表中占用的块数不同,末尾块的空闲空间差异会被计入总大小。你的实际差值81920字节正好是10个完整8KB块的大小(
10*8192=81920),这是80000字节的元组差值加上末尾块空闲空间的差异之和,符合块级对齐的统计规则。
内容的提问来源于stack exchange,提问作者Xocas17
相关产品推荐
相关产品推荐

