要将空间返回给操作系统,请使用VACUUM FULL
。我想你正在奔跑VACUUM FULL ANALYZE
。我引用该手册:
FULL
选择“完全”真空,它可以回收更多空间,但需要更长的时间并专门锁定表。此方法还需要额外的磁盘空间,因为它会写入表的新副本,并且在操作完成之前不会释放旧副本。通常,仅在需要从表中回收大量空间时才应使用此选项。
大胆强调我的。
CLUSTER
作为附带效果也可以达到目的。
Plain VACUUM
通常无法实现您的目标(“表末尾的一个或多个页面完全免费”)。它不会对行进行重新排序,只会在机会出现时从文件的物理末尾修剪空白页,就像您在手册中的引用一样。
INSERT
一批行时,您可以在物理文件的末尾获得空页,并且DELETE
在添加其他元组之前可以得到空页。或者,如果删除了足够多的行,可能会偶然发生。
还有一些特殊设置可能会阻止VACUUM FULL
回收空间。看到:
在表格末尾准备空白页以进行测试
系统列ctid
代表一行的物理位置。您需要了解该列:
我们可以通过删除最后一页的所有行来处理它并准备一个表:
DELETE FROM tbl t
USING (
SELECT (split_part(ctid::text, ',', 1) || ',0)')::tid AS min_tid
, (split_part(ctid::text, ',', 1) || ',65535)')::tid AS max_tid
FROM tbl
ORDER BY ctid DESC
LIMIT 1
) d
WHERE t.ctid BETWEEN d.min_tid AND d.max_tid;
现在,最后一页为空。这将忽略并发写入。您要么是对该表的唯一写操作,要么需要采取写锁操作以避免干扰。
优化查询以快速识别合格行。a的第二个数字tid
是存储为unsigned的元组索引int2
,并且65535
是该类型(2^16 - 1
)的最大值,因此这是安全的上限。
SQL Fiddle(重用不同情况下的简单表。)
测量行/表大小的工具:
磁盘已满
您需要在磁盘上摆动空间才能进行任何这些操作。还有一个社区工具pg_repack
可以代替VACUUM FULL
/ CLUSTER
。它避免了排他锁,但也需要可用空间来使用。手册:
需要的可用磁盘空间是目标表和索引的两倍。
作为最后的选择,您可以运行转储/还原周期。这也消除了表和索引的所有膨胀。密切相关的问题:
那里的答案非常激进。如果您的情况允许这样做(没有外键或其他防止行删除的引用,并且没有对表的并发访问),则可以:
将表转储到具有足够磁盘空间(用于)的远程计算机所连接的磁盘上:-a
--data-only
从远程外壳中,转储表数据:
pg_dump -h <host_name> -p <port> -t mytbl -a mydb > db_mytbl.sql
在pg会话中,TRUNCATE
该表:
-- drop all indexes and constraints here for best performance
TRUNCATE mytbl;
从远程shell恢复到同一表:
psql -h <host_name> -p <port> mydb -f db_mytbl.sql
-- recreate all indexes and constraints here
现在,它没有任何死行或膨胀。
但是也许您可以更简单一些?
您可以通过删除(移动)不相关的文件来在磁盘上腾出足够的空间吗?
您可以VACUUM FULL
先逐个缩小表,以释放足够的磁盘空间吗?
您可以运行REINDEX TABLE
或REINDEX INDEX
释放to肿的索引中的磁盘空间吗?
无论您做什么,都不要着急。如有疑问,请先将所有内容备份到安全位置。