1
 CREATE TABLE test_size1 AS SELECT (random() * 1e3)::int id, (random() * 10)::smallint col1, (random() * 10)::smallint col2 FROM generate_series(1, 1e6);

 attname | typname | typalign | typlen
---------+---------+----------+--------
 id      | int4    | i        |      4
 col1    | int2    | s        |      2
 col2    | int2    | s        |      2

              metric               |  bytes   | bytes_pretty | bytes_per_row
-----------------------------------+----------+--------------+---------------
 core_relation_size                | 36249600 | 35 MB        |            36
 visibility_map                    |     8192 | 8192 bytes   |             0
 free_space_map                    |    32768 | 32 kB        |             0
 table_size_incl_toast             | 36290560 | 35 MB        |            36
 indexes_size                      |        0 | 0 bytes      |             0
 total_size_incl_toast_and_indexes | 36290560 | 35 MB        |            36
 live_rows_in_text_representation  |  8991442 | 8781 kB      |             8
 ------------------------------    |          |              |
 row_count                         |  1000000 |              |
 live_tuples                       |  1000000 |              |
 dead_tuples                       |        0 |              |

CREATE TABLE test_size3 (id int, col1 "char", col2 "char");
insert into test_size3 SELECT (random() * 1e3)::int id, chr((random() * 10)::smallint + 1) col1, chr((random() * 10)::smallint + 1) col2 FROM generate_series(1, 1e6);

 attname | typname | typalign | typlen
---------+---------+----------+--------
 id      | int4    | i        |      4
 col1    | char    | c        |      1
 col2    | char    | c        |      1

              metric               |  bytes   | bytes_pretty | bytes_per_row
-----------------------------------+----------+--------------+---------------
 core_relation_size                | 36249600 | 35 MB        |            36
 visibility_map                    |     8192 | 8192 bytes   |             0
 free_space_map                    |    32768 | 32 kB        |             0
 table_size_incl_toast             | 36290560 | 35 MB        |            36
 indexes_size                      |        0 | 0 bytes      |             0
 total_size_incl_toast_and_indexes | 36290560 | 35 MB        |            36
 live_rows_in_text_representation  |  9894817 | 9663 kB      |             9
 ------------------------------    |          |              |
 row_count                         |  1000000 |              |
 live_tuples                       |  1000000 |              |
 dead_tuples                       |        0 |              |

I expected test_size1 and test_size3 tables would have different sizes (test_size2 should be smaller by 2 bytes per row). However it's not the case, they have identical sizes, even though smallint is supposed to occupy 2 bytes while "char" is only 1 byte. It looks like I'm missing something, please share if you know the root cause of this behaviour (I've checked pg13 and pg14).

(upd #1) I've created new tables test_size11 and test_size33, just to make sure nothing weird is happening because columns in previous tables were nullable. Sizes remained exactly the same - I'll omit the details.

             Table "public.test_size11"
 Column |   Type   | Collation | Nullable | Default
--------+----------+-----------+----------+---------
 id     | integer  |           | not null |
 col1   | smallint |           | not null |
 col2   | smallint |           | not null |

            Table "public.test_size33"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 id     | integer |           | not null |
 col1   | "char"  |           | not null |
 col2   | "char"  |           | not null |

Alignment padding shouldn't be the issue, given the order and type of columns.

3
  • 1
    Alignment and padding, see e.g. here: dba.stackexchange.com/a/267424 Commented Feb 10, 2023 at 10:46
  • 4
    Does this answer your question? How to determine or predict space on disk per table row? Commented Feb 10, 2023 at 11:18
  • If this link have explanation for this - I don't see it. As far as I understand, there should be 0 alignment padding in both tables. Commented Feb 10, 2023 at 12:26

1 Answer 1

1

I think you forget that the tuple itself must me maxaligned, so there could be padding between the tuples that swallows the space you are saving.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.