web-dev-qa-db-ja.com

アライメントの最適化されたテーブルが元のテーブルよりも大きいのはなぜですか?

別の質問 では、スペースを節約し、パフォーマンスを向上させるために、テーブルの1つからレイアウトを最適化する必要があることを学びました。私はこれを行いましたが、以前よりも大きなテーブルになり、パフォーマンスは変わりませんでした。もちろん、_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
_

_real3d_が次のように定義されている場合

_CREATE TYPE real3d AS (
  x real,
  y real,
  z real);
_

このレイアウトを次のように変更しました。

_                                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    |
_

私が間違っていない場合は、1行あたり66バイトを節約する必要があります(138は元の1行、72は新しい行です)。ただし、これは発生していません。これらのテーブルに7604913がある場合、元のテーブルのサイズは1020 MBでした。新しいテーブルのサイズは1159 MBです。サイズの測定にはpg_size_pretty(pg_relation_size('<tablename>'))を使用しました。では、何が欠けているのでしょうか?

注:最後の4つの列以外はすべて別のテーブルから継承されます(もちろん、私もレイアウトを変更する必要がありました)。

更新:Erwin Brandstetterの提案に従って_VACUUM FULL_を実行した後、新しいテーブルに必要なのは734 MBだけです。

5
tomka

物理テーブルのサイズは通常、VACUUM(またはVACUUM ANALYZE)を実行しても削減されません(テーブルの末尾からのリムーバブルページの日和見主義的プルーニングを除く)。実際にテーブルを縮小するには、 VACUUM FULL を実行する必要があります。

テーブルに書き込み負荷がある場合、これは必ずしも定期的に実行したいことではありません。デッド行は、UPDATEが更新された行のバージョンを同じデータページに配置するための小刻みな余裕を提供し、これによりパフォーマンスが向上します。リレーションの物理テーブルを縮小および拡大するためのコストもあります。さらに、VACUUM FULLは、テーブルの排他ロックを取り出します。
そのため、自動バキュームはVACUUM(およびANALYZE)のみを実行し、VACUUM FULLは実行しません。

ただし、読み取り専用(またはほとんど読み取り)のテーブルは、最小サイズに保つのが最適です。また、テーブル定義を変更した後(またはその他の理由で)の過度の膨張は、すぐに削除することもできます。

テーブルの両方のバージョンでVACUUM FULLを試して、もう一度測定してください。違いがわかるはずです。

行/テーブルのサイズの詳細については、 複数のテストを使用したクエリ を試すこともできます。

7