pg_column_size(table.*) 和 pg_column_size(table.col1) + pg_column_size (table.col2) 的区别

Lua*_*ynh 8 postgresql

来自PG DOC

pg_column_size(any) :用于存储特定值(可能是压缩的)的字节数 pg_column_size 显示用于存储任何单个数据值的空间

例子:

select pg_column_size(5::smallint);    -- 2 bytes 
select pg_column_size(5::int);         -- 4 bytes 
Run Code Online (Sandbox Code Playgroud)

输入pg_column_size,它可以是一列或一行,所以我创建了一个测试来检查它。这是我的测试:

我的桌子

CREATE TABLE index_test
(
  id integer NOT NULL,  -- 4  bytes 
  a integer,            -- 4  bytes 
  b integer,            -- 4  bytes 
  CONSTRAINT index_test_id PRIMARY KEY (id)
)
Run Code Online (Sandbox Code Playgroud)

1/ 第一个查询: sum(pg_column_size(table.rows))

with abc as 
(
 select id,a,b
 from index_test where b > 100
)
select pg_size_pretty(sum(pg_column_size(abc.*))) from abc  -- "348 kB", abc.* = record
Run Code Online (Sandbox Code Playgroud)

和查询的解释:

"Aggregate  (cost=427.55..427.56 rows=1 width=24) (actual time=9.171..9.171 rows=1 loops=1)"
"  CTE abc"
"    ->  Seq Scan on index_test  (cost=0.00..180.00 rows=9902 width=12) (actual time=0.039..2.882 rows=9902 loops=1)"
"          Filter: (b > 100)"
"  ->  CTE Scan on abc  (cost=0.00..198.04 rows=9902 width=24) (actual time=0.047..7.151 rows=9902 loops=1)"
"Total runtime: 9.376 ms"
Run Code Online (Sandbox Code Playgroud)

2/ 第二个查询: sum(pg_column_size(table.id)) + sum(pg_column_size(table.a)) + sum(pg_column_size(table.b))

with abc as 
(
 select id, a, b 
 from index_test where b > 100
)
select  pg_size_pretty((sum(pg_column_size(id)))  + (sum(pg_column_size(b))) + (sum(pg_column_size(a))))
from abc  -- "116 kB"
Run Code Online (Sandbox Code Playgroud)

和查询的解释:

"Aggregate  (cost=526.57..526.59 rows=1 width=12) (actual time=10.959..10.959 rows=1 loops=1)"
"  CTE abc"
"    ->  Seq Scan on index_test  (cost=0.00..180.00 rows=9902 width=12) (actual time=0.035..2.780 rows=9902 loops=1)"
"          Filter: (b > 100)"
"  ->  CTE Scan on abc  (cost=0.00..198.04 rows=9902 width=12) (actual time=0.039..5.623 rows=9902 loops=1)"
"Total runtime: 11.173 ms"
Run Code Online (Sandbox Code Playgroud)

3/ 结果:

第一个查询:348 KB

第二个查询:116 KB ( pg_column_size(id) = 39 KB ...)

我认为两个查询都必须返回相同的结果,但是第一个查询的大小 = 3 * 第二个查询的大小,这让我感到困惑。在第一个解释中,“宽度= 24字节/行”(而不是12),我想知道为什么它是增加的,我认为这是问题的线索。到目前为止,我找不到明确的答案,请帮助我。

dez*_*zso 10

24 字节/行的差异敲响了警钟:它与表和索引中的行头大小相同。直到您的问题我才意识到相同的标题大小显然适用于您在查询中返回的每一行:

SELECT pg_column_size((1::integer, 2::smallint));
 pg_column_size 
????????????????
             30
Run Code Online (Sandbox Code Playgroud)

SELECT pg_column_size(1::integer) + pg_column_size(1::smallint) AS pg_column_size;
 pg_column_size 
????????????????
              6
Run Code Online (Sandbox Code Playgroud)

将一行传递给 时pg_column_size(),它会计算整行的大小,包括标题。

现在再深入一点,你会发现一些有趣的事实。

例如,可以检查将列填充到最接近的 4 个字节(其中 k 是正整数)所引起的差异:

SELECT pg_column_size((1::smallint, 2::integer));
 pg_column_size 
????????????????
             32
Run Code Online (Sandbox Code Playgroud)

这里我们比第一个例子多了两个字节,smallint 之后剩下的 2 个字节被“浪费”了。在大表中选择列的顺序时,这可能很重要 - 例如,我们可以将某些内容挤入“空”空间:

SELECT pg_column_size((1::smallint, FALSE, FALSE, 2::integer));
 pg_column_size 
????????????????
             32
Run Code Online (Sandbox Code Playgroud)

另一个重要的事情是具有 NULL 作为值的列在此处具有零大小:

SELECT pg_column_size((NULL::smallint, 2::integer));
 pg_column_size 
????????????????
             28
Run Code Online (Sandbox Code Playgroud)

相比之下,当尝试单独添加列时,您将获得 NULL 结果:

SELECT pg_column_size(NULL::smallint) +  pg_column_size(2::integer) AS pg_column_size;
 pg_column_size 
????????????????
           NULL
Run Code Online (Sandbox Code Playgroud)