对齐优化表比原始表大 - 为什么?

tom*_*mka 5 postgresql database-design datatypes disk-space vacuum

另一个问题中,我了解到我应该从我的一个表中优化布局以节省空间并获得更好的性能。我这样做了,但最终得到了比以前更大的表,并且性能没有改变。当然我做了一个VACUUM ANALYZE. 怎么会?

(我看到如果我只索引单列,索引大小不会改变。)

这是我来自的表(我添加了尺寸 + 填充):

                               Table "public.treenode"
    Column     |           Type           | Size |          Modifiers
---------------+--------------------------+------+-------------------------------
 id            | bigint                   | 8    | not null default nextval( ...
 user_id       | integer                  | 4+4  | not null
 creation_time | timestamp with time zone | 8    | not null default now()
 edition_time  | timestamp with time zone | 8    | not null default now()
 project_id    | integer                  | 4    | not null
 location      | real3d                   | 36   | not null
 editor_id     | integer                  | 4+4  |
 parent_id     | bigint                   | 8    |
 radius        | real                     | 4    | not null default 0
 confidence    | smallint                 | 2    | not null default 5
 skeleton_id   | integer                  | 4    | not null
Run Code Online (Sandbox Code Playgroud)

随着real3d被定义为

CREATE TYPE real3d AS (
  x real,
  y real,
  z real);
Run Code Online (Sandbox Code Playgroud)

我将此布局更改为以下内容:

                                Table "public.treenode_new"
    Column     |           Type           | Size |            Modifiers
---------------+--------------------------+------+--------------------------------
 id            | bigint                   | 8    | not null default nextval(' ...
 project_id    | integer                  | 4    | not null
 location_x    | real                     | 4    | not null
 location_y    | real                     | 4    | not null
 location_z    | real                     | 4    | not null
 editor_id     | integer                  | 4    | not null
 user_id       | integer                  | 4    | not null
 creation_time | timestamp with time zone | 8    | not null default now()
 edition_time  | timestamp with time zone | 8    | not null default now()
 skeleton_id   | integer                  | 4    | not null
 radius        | real                     | 4    | not null default 0
 confidence    | real                     | 4+4  | not null default 5
 parent_id     | bigint                   | 8    |
Run Code Online (Sandbox Code Playgroud)

如果我没记错的话,我应该每行节省 66 个字节(138 是一个原始行,72 是一个新行)。然而,这并没有发生:这些表中有 7604913,原始表的大小为 1020 MB。新表的大小为 1159 MB。我曾经pg_size_pretty(pg_relation_size('<tablename>'))测量过尺寸。那么我错过了什么?

一个注意事项:除了最后四列之外的所有列都是从另一个表继承的(我当然也不得不更改其中的布局)。

更新:VACUUM FULL按照 Erwin Brandstetter 的建议运行后,新表只需要 734 MB。

Erw*_*ter 7

物理表的大小通常(除了从表末尾的可移动页面的机会修剪外)不会通过运行VACUUM(或VACUUM ANALYZE)来减少。您需要运行VACUUM FULL以实际缩小表。

如果您的表上有写负载,这不一定是您想要定期执行的操作。死行为UPDATE提供了摆动空间,以将更新的行版本放在同一数据页上,从而获得更好的性能。缩小和扩大关系的物理表也是有代价的。另外,VACUUM FULL取出表上的排他锁
这就是为什么 autovacuum 只运行VACUUM(和ANALYZE) 不运行VACUUM FULL

不过,只读(或大部分读取)表最好保持在其最小大小。更改表定义(或出于其他原因)后的过度膨胀也最好立即删除。

尝试VACUUM FULL使用两个版本的表格并再次测量。差异应该显示出来。

您还可以通过多个测试尝试我的查询,以获取有关行/表大小的更多信息。