pg的页面初始化默认值为8192,除去页面头信息之外可以使用的空间约为8160字节,当某一个tuple超过这个大小后,就会出现上述报错。
什么情况下会出现这种报错呢?
我举个栗子
首先是字段数量要足够大,注意不要超过最大字段数1600。例如我们建个1500字段的
-bash-4.2$ cat create_table.sh
#!/bin/bash
sql=idMbigint
for ((i=0;i<1500;i++))
do
sql=${sql}Fid_${i}Mbigint
done
column=`echo $sql|sed 's/M/ /g'|sed 's/F/,/g'`
sql="create table tp ($column);"
echo $sql
-bash-4.2$ ./create_table.sh |psql
CREATE TABLE
-bash-4.2$
然后,字段类型大小乘字段数要大于8160字节,这里bigint 8字节*1501=12008字节,在加上元组头信息,妥妥的超过了。
插入试试
-bash-4.2$ cat insert_table.sh
#!/bin/bash
sql=10
for ((i=0;i<1500;i++))
do
sql=${sql}F${i}
done
column=`echo $sql|sed 's/F/,/g'`
sql="insert into tp values ($column);"
echo $sql
-bash-4.2$ ./insert_table.sh |psql
ERROR: row is too big: size 12032, maximum size 8160
-bash-4.2$
出现了,就是这个报错。解决这个问题有两种方法,一种是从数据库着手初始化页面时设置大一些,比如32K,另一个就是从应用着手修改表结构,要么缩减字段数量要么修改字段类型,总之表结构肯定是要重建的。
其实刚开始发现这个问题还是挺懵逼的,pg自带的toast机制一度让我掉到沟里去了,翻了翻才发现toast的启用是根据字段的大小来决定的,例如单字段char或者varchar超过501,就会启用toast机制,或者text字段当插入长度超过2560的时候才启用toast机制。当然这个也和字段数量有关,当字段数量增多时,启用toast机制的临界值就会降低。总的来说当一条元组超过2KB的时候,PG就会考虑是否启用toast机制。
其实常用的数据类型,INT,BIGINT,REAL,FLOAT...应该是不会启用toast的,如果启用了toast,那存在原先位置处数据变成一个地址或者OID,相比也不会小多少。
参考博客:
https://www.qcloud.com/community/article/164816001481011925