我有一个简单的例子,其中pg_column_size报告的值非常不同。我认为这与它是否正在考虑TOASTed值有关,但我不确定。这是设置:
CREATE TABLE foo (bar TEXT);
INSERT INTO foo (bar) VALUES (repeat('foo', 100000));
SELECT pg_column_size(bar) as col, pg_column_size(foo.*) as table FROM foo;
我在Postgres 9.6中看到的是,
col table
3442 300028
这里存在一个数量级的差异。思考?我计算行的大小的正确方法是什么?我有一个想法是,
SELECT pg_column_size(bar), pg_column_size(foo.*) - octet_length(bar) + pg_column_size(bar) FROM foo;
哪个应该减去TOAST后尺寸并添加TOAST尺寸。
修改:我建议的解决方法仅适用于字符列,例如不适用于JSONB。
答案 0 :(得分:1)
第一个值是TOASTed值的压缩大小,而第二个值是整行的未压缩大小。
SELECT 'foo'::regclass::oid;
┌───────┐
│ oid │
├───────┤
│ 36344 │
└───────┘
(1 row)
SELECT sum(length(chunk_data)) FROM pg_toast.pg_toast_36344;
┌──────┐
│ sum │
├──────┤
│ 3442 │
└──────┘
(1 row)
foo.*
(或者foo
)是PostgreSQL中的“wholerow引用”,其数据类型为foo
(在创建表时创建)。
PostgreSQL知道foo.bar
存储在外部,所以它返回它在TOAST表中的大小,但foo
(复合类型)不是,所以你得到总数大小
请参阅src/backend/access/heap/tuptoaster.c
中的相关代码:
Size
toast_datum_size(Datum value)
{
struct varlena *attr = (struct varlena *) DatumGetPointer(value);
Size result;
if (VARATT_IS_EXTERNAL_ONDISK(attr))
{
/*
* Attribute is stored externally - return the extsize whether
* compressed or not. We do not count the size of the toast pointer
* ... should we?
*/
struct varatt_external toast_pointer;
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
result = toast_pointer.va_extsize;
}
[...]
else
{
/*
* Attribute is stored inline either compressed or not, just calculate
* the size of the datum in either case.
*/
result = VARSIZE(attr);
}
return result;
}