清理 PG 表中的行后未释放磁盘空间

Has*_*aig 11 postgresql postgresql-9.3

我知道空间不会突然释放(除非有TRUNCATE)。但是这个在我看来很不正常。

postgresql (9.3.10) 表在删除了 70% 的记录后没有释放空间的原因是什么?

我有一张桌子叫user_sessions_session. 顾名思义,它为 Web 应用程序的每个用户存储会话数据。

它的原始尺寸是:

              Table               |  Size   | External Size 
----------------------------------+---------+---------------
 user_sessions_session            | 15 GB   | 13 GB
Run Code Online (Sandbox Code Playgroud)

此后,我删除了 3 个月前的所有用户会话。这是表中的大部分行。这是 3 天前。我刚刚再次检查了表的大小,这是我看到的:

              Table               |  Size   | External Size 
----------------------------------+---------+---------------
 user_sessions_session            | 15 GB   | 13 GB
Run Code Online (Sandbox Code Playgroud)

此外,select * from pg_stat_activity where query like 'autovacuum:%';显示此时没有进行吸尘。

顺便说一句,我以前在同一个会话表上遇到过同样的问题 - 这不是一次性的。


以防万一,这是我用来获取表大小的 SQL(user_sessions_session 在列表中显示为第 1):

SELECT                                                         
   relname as "Table",
   pg_size_pretty(pg_total_relation_size(relid)) As "Size",
   pg_size_pretty(pg_total_relation_size(relid) - pg_relation_size(relid)) as "External Size"
   FROM pg_catalog.pg_statio_user_tables ORDER BY pg_total_relation_size(relid) DESC;
Run Code Online (Sandbox Code Playgroud)

Eva*_*oll 16

文档中,

在 PostgreSQL 中,行的 UPDATE 或 DELETE 不会立即删除该行的旧版本。这种方法对于获得多版本并发控制(MVCC,参见第 13 章)的好处是必要的:当行版本仍然可能对其他事务可见时,不得删除它。但最终,任何事务都不再对过时或已删除的行版本感兴趣。然后必须回收它占用的空间以供新行重用,以避免磁盘空间需求的无限增长。这是通过运行VACUUM.

在所有。绝不。没有例外。当您删除一行时,您实际上将其标记为快照的非活动状态。之前事务启动的其他快照仍然可以看到它。这意味着它仍在磁盘上。

行不存储在它们自己的磁盘文件中。为了删除该行,即使在需要时,您也必须重写存储在磁盘上的没有该行的文件。DELETE不这样做,在正常情况下,这是完全正常的,因为这是不可见的事务死行可以回收利用内部通过一个简单的VACUUM。被标记为重用后的新数据可以存储在堆中。

所以本质上,只有在内部导致表的堆被重写的操作才能回收空间。这些操作是:

  • CLUSTER
  • VACUUM FULL
  • TRUNCATE
  • ALTER TABLE (重写表格的表格)

所有这些操作都需要ACCESS EXCLUSIVE锁。而且,TRUNCATE是这样的大锤,它甚至违反了 MVCC

@EvanCarroll:从技术上讲,即使在这里删除了大量行,我实际上也可以耗尽磁盘空间?– Hassan Baig 1 分钟前

是的,真的,技术上和其他所有方面,但让我们对上述内容做一个特别的警告。如果你DELETE有一堆行并提交,它们会被标记为不活动。当您VACUUM回收表的堆空间时。从那时起,要耗尽磁盘空间,您可以

  • 耗尽该表堆上的回收空间,因为 PostgreSQL 只会在该空间中存储内容。
  • 或者,耗尽不同表的堆。

但是,当您耗尽磁盘空间时,可能会发生非常糟糕的事情。而且,每个MVCC 数据库供应商都会发生这种情况。简单地说,不要耗尽磁盘空间