Postgres将列从TEXT更改为INTEGER会增加表的大小

时间:2018-11-05 22:13:47

标签: postgresql

我有一个postgres表,它具有这样的模式

                                              Table "am.old_product"
     Column      |           Type           | Collation | Nullable | Default | Storage  | Stats target | Description 
-----------------+--------------------------+-----------+----------+---------+----------+--------------+-------------
 p_config_sku    | text                     |           |          |         | extended |              | 
 p_simple_sku    | text                     |           |          |         | extended |              | 
 p_merchant_id   | text                     |           |          |         | extended |              | 
 p_country       | character varying(2)     |           |          |         | extended |              | 
 p_discount_rate | numeric(10,2)            |           |          |         | main     |              | 
 p_black_price   | numeric(10,2)            |           |          |         | main     |              | 
 p_red_price     | numeric(10,2)            |           |          |         | main     |              | 
 p_received_at   | timestamp with time zone |           |          |         | plain    |              | 
 p_event_id      | uuid                     |           |          |         | plain    |              | 
 p_is_deleted    | boolean                  |           |          |         | plain    |              | 
Indexes:
    "product_p_simple_sku_p_country_p_merchant_id_idx" UNIQUE, btree (p_simple_sku, p_country, p_merchant_id)
    "config_sku_country_idx" btree (p_config_sku, p_country)

我们认为,删除TEXT字段mercant_id并将其移动到另一个表,并使用外键在产品表中引用它是一个更好的主意。因此,新架构看起来像这样。

                                                  Table "am.product"
      Column       |           Type           | Collation | Nullable | Default | Storage  | Stats target | Description 
-------------------+--------------------------+-----------+----------+---------+----------+--------------+-------------
 p_config_sku      | text                     |           | not null |         | extended |              | 
 p_simple_sku      | text                     |           | not null |         | extended |              | 
 p_country         | character varying(2)     |           | not null |         | extended |              | 
 p_discount_rate   | numeric(10,2)            |           |          |         | main     |              | 
 p_black_price     | numeric(10,2)            |           |          |         | main     |              | 
 p_red_price       | numeric(10,2)            |           |          |         | main     |              | 
 p_received_at     | timestamp with time zone |           | not null |         | plain    |              | 
 p_event_id        | uuid                     |           | not null |         | plain    |              | 
 p_is_deleted      | boolean                  |           |          | false   | plain    |              | 
 p_merchant_id_new | integer                  |           | not null |         | plain    |              | 
Indexes:
    "new_product_p_simple_sku_p_country_p_merchant_id_new_idx" UNIQUE, btree (p_simple_sku, p_country, p_merchant_id_new)
    "p_config_sku_country_idx" btree (p_config_sku, p_country)
Foreign-key constraints:
    "fk_merchant_id" FOREIGN KEY (p_merchant_id_new) REFERENCES am.merchant(m_id)

现在,这应该使产品表的尺寸正确吗?我们使用的是4个字节的整数,而不是TEXT。事实并非如此,两个表具有相同的确切行数。产品表(带有一个整数字段)的大小为34.3 GB。旧表的大小(带有TEXT)为19.7GB

有人对此有解释吗?

2 个答案:

答案 0 :(得分:0)

您可以通过各种ALTER TABLE命令强制执行至少一次重写整个表的操作。

未使用的空间将逐渐重新使用,或者为了更迅速地进行更改,请尝试在表上使用CLUSTERVACUUM FULL

答案 1 :(得分:0)

查看VACUUM命令。

数据库文件是元组的有组织的集合。一行可以由一个或多个元组组成。添加新列时,将元组添加到表文件中。但是,当您删除一列时,元组会占用空间,因为从文件中删除它是一项昂贵的操作。他们是死元组。

 VACUUM FULL am.product;

不幸的是,这将在表上创建排他锁,您将无法在该过程中查询它。