In another question I learned that I should optimize the layout from one of my tables to save space and have better performance. I did this, but ended up with a larger table than before and performance did not change. Of course I did a VACUUM ANALYZE. How comes?
(I see that the index sizes won't change if I only index single columns.)
This is the table I was coming from (I've added sizes + padding):
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
With real3d being defined as
CREATE TYPE real3d AS (
x real,
y real,
z real);
I changed this layout to the following:
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 |
If I am not mistaken, I should save 66 bytes per row (138 is one original row, 72 is a new row). This however is not happening: With 7604913 in these tables, the original table had a size of 1020 MB. The new table has a size of 1159 MB. I used pg_size_pretty(pg_relation_size('<tablename>')) to measure the sizes. So what am I missing?
One note: all but the last four columns are inherited from another table (of which I of course had to change the layout, too).
Update: After running VACUUM FULL as suggested by Erwin Brandstetter, the new table needs only 734 MB.
2+2and4+4. Each tuple is padded to the nextMAXALIGNat the end. Plus, remember that actual NULL columns are not stored at all. Just an entry in the null bitmask - which may also change the padding on following values. – Erwin Brandstetter Jul 31 '14 at 20:01real3dis actually33+3(compare to fiddle for your last Q). The padding between tuples does not show inpg_column_size(t). All-in-all your old rows with all values NOT NULL (no null bitmask) occupied 128 bytes on disk (not 138) and the new one 72 as you wrote. That's 56 bytes per row. And would amount to saving ~ 406 MB (SELECT pg_size_pretty(56.0 * 7604913)). Did you change anything else, or are thereNULLvalues involved? – Erwin Brandstetter Jul 31 '14 at 20:34parent_idcolumn contains many null values (433761). – tomka Jul 31 '14 at 20:38