suminb / finance

경제적 자유로의 여정

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Numeric type

suminb opened this issue · comments

Outline

We are currently using a numeric(20, 4) type to store monetary values, but numeric(10, 4) should be enough. We would like to see such a change will decrease the amount of storage space needed and potentially increase the overall performance.

https://www.postgresql.org/docs/9.1/static/datatype-numeric.html

Counting the number of bytes per row

WITH x AS (
   SELECT count(*)               AS ct
        , sum(length(t::text))   AS txt_len  -- length in characters
        , 'asset_value'::regclass AS tbl  -- provide (qualified) table name here
   FROM  asset_value t  -- ... and here
   )
, y AS (
   SELECT ARRAY [pg_relation_size(tbl)
               , pg_relation_size(tbl, 'vm')
               , pg_relation_size(tbl, 'fsm')
               , pg_table_size(tbl)
               , pg_indexes_size(tbl)
               , pg_total_relation_size(tbl)
               , txt_len
             ] AS val
        , ARRAY ['core_relation_size'
               , 'visibility_map'
               , 'free_space_map'
               , 'table_size_incl_toast'
               , 'indexes_size'
               , 'total_size_incl_toast_and_indexes'
               , 'live_rows_in_text_representation'
             ] AS name
   FROM   x
   )
SELECT unnest(name)                AS what
     , unnest(val)                 AS "bytes/ct"
     , pg_size_pretty(unnest(val)) AS bytes_pretty
     , unnest(val) / ct            AS bytes_per_row
FROM   x, y

UNION ALL SELECT '------------------------------', NULL, NULL, NULL
UNION ALL SELECT 'row_count', ct, NULL, NULL FROM x
UNION ALL SELECT 'live_tuples', pg_stat_get_live_tuples(tbl), NULL, NULL FROM x
UNION ALL SELECT 'dead_tuples', pg_stat_get_dead_tuples(tbl), NULL, NULL FROM x;

See https://dba.stackexchange.com/questions/23879/measure-the-size-of-a-postgresql-table-row for more details.

Result

               what                | bytes/ct | bytes_pretty | bytes_per_row 
-----------------------------------+----------+--------------+---------------
 core_relation_size                |  4669440 | 4560 kB      |           104
 visibility_map                    |     8192 | 8192 bytes   |             0
 free_space_map                    |    24576 | 24 kB        |             0
 table_size_incl_toast             |  4702208 | 4592 kB      |           105
 indexes_size                      |  4227072 | 4128 kB      |            94
 total_size_incl_toast_and_indexes |  8929280 | 8720 kB      |           199
 live_rows_in_text_representation  |  5046614 | 4928 kB      |           112
 ------------------------------    |          |              |              
 row_count                         |    44668 |              |              
 live_tuples                       |    44668 |              |              
 dead_tuples                       |     1186 |              |              
(11 rows)

Take 1

Plans

  1. Clone the current table (asset_value) as asset_value_cloned.
  2. Alter the numeric(20, 4) columns as numeric(10, 4).
  3. Run the same query to see if there is any sign of improvement.

Result

The entire table has been cloned as

CREATE TABLE asset_value_cloned AS SELECT * FROM asset_value

Interestingly, the table size has been shrunk. It's probably because there is no dead_tuples in the cloned table.

                           List of relations
 Schema |        Name        | Type  | Owner  |    Size    | Description 
--------+--------------------+-------+--------+------------+-------------
 public | asset_value        | table |        | 4592 kB    | 
 public | asset_value_cloned | table |        | 4408 kB    | 

As a result, the average row size got smaller. (104 -> 101 bytes)

               what                | bytes/ct | bytes_pretty | bytes_per_row 
-----------------------------------+----------+--------------+---------------
 core_relation_size                |  4513792 | 4408 kB      |           101
 visibility_map                    |        0 | 0 bytes      |             0
 free_space_map                    |        0 | 0 bytes      |             0
 table_size_incl_toast             |  4513792 | 4408 kB      |           101
 indexes_size                      |        0 | 0 bytes      |             0
 total_size_incl_toast_and_indexes |  4513792 | 4408 kB      |           101
 live_rows_in_text_representation  |  5046614 | 4928 kB      |           112
 ------------------------------    |          |              |              
 row_count                         |    44668 |              |              
 live_tuples                       |    44668 |              |              
 dead_tuples                       |        0 |              |              
(11 rows)

We altered the type of the numeric columns as follows.

ALTER TABLE asset_value_cloned ALTER open TYPE numeric(10, 4);
ALTER TABLE asset_value_cloned ALTER high TYPE numeric(10, 4);
ALTER TABLE asset_value_cloned ALTER low TYPE numeric(10, 4);
ALTER TABLE asset_value_cloned ALTER close TYPE numeric(10, 4);

No luck. The table size remains unaffected.

               what                | bytes/ct | bytes_pretty | bytes_per_row 
-----------------------------------+----------+--------------+---------------
 core_relation_size                |  4513792 | 4408 kB      |           101
 visibility_map                    |        0 | 0 bytes      |             0
 free_space_map                    |        0 | 0 bytes      |             0
 table_size_incl_toast             |  4513792 | 4408 kB      |           101
 indexes_size                      |        0 | 0 bytes      |             0
 total_size_incl_toast_and_indexes |  4513792 | 4408 kB      |           101
 live_rows_in_text_representation  |  5046614 | 4928 kB      |           112
 ------------------------------    |          |              |              
 row_count                         |    44668 |              |              
 live_tuples                       |    44668 |              |              
 dead_tuples                       |        0 |              |              
(11 rows)

Take 2

Plans

  1. Create a new, empty table with a new column type (numeric(10, 4)).
  2. Copy over the entire data set into the new table.

Result

CREATE TABLE asset_value_cloned (
    id bigint NULL,
    asset_id bigint NULL,
    base_asset_id bigint NULL,
    evaluated_at timestamp without time zone NULL,
    source asset_value_source NULL,
    granularity granularity NULL,
    open numeric(10,4) NULL,
    high numeric(10,4) NULL,
    low numeric(10,4) NULL,
    close numeric(10,4) NULL,
    volume integer NULL);
INSERT INTO asset_value_cloned SELECT * FROM asset_value;
               what                | bytes/ct | bytes_pretty | bytes_per_row 
-----------------------------------+----------+--------------+---------------
 core_relation_size                |  4513792 | 4408 kB      |           101
 visibility_map                    |        0 | 0 bytes      |             0
 free_space_map                    |    24576 | 24 kB        |             0
 table_size_incl_toast             |  4538368 | 4432 kB      |           101
 indexes_size                      |        0 | 0 bytes      |             0
 total_size_incl_toast_and_indexes |  4538368 | 4432 kB      |           101
 live_rows_in_text_representation  |  5046614 | 4928 kB      |           112
 ------------------------------    |          |              |              
 row_count                         |    44668 |              |              
 live_tuples                       |    44668 |              |              
 dead_tuples                       |        0 |              |              
(11 rows)

No changes in terms of bytes_per_row after the alteration. We will put this one on halt and re-visit in the future.