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。被标记为重用后的新数据可以存储在堆中。
所以本质上,只有在内部导致表的堆被重写的操作才能回收空间。这些操作是:
CLUSTERVACUUM FULLTRUNCATEALTER TABLE (重写表格的表格)所有这些操作都需要ACCESS EXCLUSIVE锁。而且,TRUNCATE是这样的大锤,它甚至违反了 MVCC。
@EvanCarroll:从技术上讲,即使在这里删除了大量行,我实际上也可以耗尽磁盘空间?– Hassan Baig 1 分钟前
是的,真的,技术上和其他所有方面,但让我们对上述内容做一个特别的警告。如果你DELETE有一堆行并提交,它们会被标记为不活动。当您VACUUM回收表的堆空间时。从那时起,要耗尽磁盘空间,您可以
但是,当您耗尽磁盘空间时,可能会发生非常糟糕的事情。而且,每个MVCC 数据库供应商都会发生这种情况。简单地说,不要耗尽磁盘空间。