VACUUM FULL

来自 PostgreSQL 维基
跳转到导航跳转到搜索


此页面包含 **历史信息或已弃用的文章**。



此文档已在 PostgreSQL 9.0 及更高版本中过时。大多数内容仅适用于 PostgreSQL 8.4 及更低版本。


VACUUM 与 VACUUM FULL(PostgreSQL 8.4 及更早版本)


此文档已在 PostgreSQL 9.0 及更高版本中过时。大部分内容仅适用于 PostgreSQL 8.4 及更低版本。


VACUUM 命令和相关的自动清理进程是 PostgreSQL 用于控制 MVCC 膨胀的方式。VACUUM 命令有两个主要形式 - 普通 VACUUMVACUUM FULL。这两个命令实际上是截然不同的,不应该混淆。

VACUUM 扫描一个表,将不再需要的元组标记为可用空间,以便它们可以被新插入或更新的数据覆盖。参见 VACUUM、ANALYZE、EXPLAIN 和 COUNT 简介 和 PostgreSQL 文档关于 MVCC 的详细说明。请注意,您很少需要在现代 PostgreSQL 数据库上直接使用 VACUUM 命令,因为 自动清理 如果设置正确,应该会为您处理这些问题。

VACUUM FULLVACUUM 不同,它会处理未被删除的数据。在 9.0 之前的 PostgreSQL 版本中,它会将数据移动到文件中先前被释放的更早空间。一旦它在文件末尾创建了可用空间,它就会截断文件,以便操作系统知道空间是可用的,可以用于其他用途。这种方式移动正在使用的数据可能会产生负面影响,包括占用大量重量级锁、增加 I/O 以及增加索引膨胀。在较旧的系统上,如果您需要释放空间,有更好的方法,以及更好的优化表方法(见下文),因此您应该基本不应在 9.x 之前的系统上使用 VACUUM FULL。即使在 9.x 及更高版本上,系统的设计目标也是您应该避免定期运行 VACUUM FULL,这样做会导致一些成本,例如大量的 WAL 归档输出和对任何流式复制服务器的高负载。

为了清楚起见,9.0 更改了 VACUUM FULL。如 文档 中所述,VACUUM FULL 的实现已更改为类似于在旧版本中使用 CLUSTER 的实现。这与此处描述的旧版 VACUUM FULL 相比,提供了一组略微不同的权衡。虽然通过此更改已消除通过索引膨胀使数据库变慢的可能性,但由于 VACUUM FULL 的锁定和整体性能开销,您可能仍然希望避免这样做。

何时使用 VACUUM FULL,何时不使用

许多人,要么根据网络上误导性的建议,要么根据“必须更好”的假设,会定期在他们的表上运行 VACUUM FULL。这通常是不推荐的,在某些情况下,会使您的数据库变慢,而不是更快。

VACUUM FULL 仅在您有一个表主要是死行时才需要 - 也就是说,其内容的大部分已经被删除。不应将其用于表优化或定期维护,因为它通常是适得其反的。在大多数情况下,释放的空间将很快重新分配,可能会增加文件系统级别的碎片,并需要比在表内重新使用现有可用空间更慢的文件系统空间分配。

当您在表上运行 VACUUM FULL 时,该表将在操作期间被锁定,因此其他任何内容都无法使用该表。VACUUM FULL 比普通 VACUUM 慢得多,因此该表可能在一段时间内不可用。

更重要的是,在 9.0 之前的系统上,虽然 VACUUM FULL 会压缩表,但它不会压缩索引 - 实际上可能会增加它们的大小,从而减慢它们的速度,在使用索引时导致更多的磁盘 I/O,并增加它们所需的内存量。在 9.0 之前的 PostgreSQL 版本中,可能需要在 VACUUM FULL 之后运行 REINDEX。请参见主文档中的 有关 VACUUM 与 VACUUM FULL 的说明

替代方案

如果您不应定期使用 VACUUM FULL(或在 9.0 之前的版本中根本不使用它)... 您应该使用什么?

自动清理

如果 自动清理 运行得足够频繁且足够积极,您的表不应该因为未回收的死行而增长(“膨胀”),因此您不应该需要将“死”空间返回给操作系统。

自动清理在每个 PostgreSQL 版本中都在不断改进,这是一个确保您运行最新版本的非常好的理由。例如,在 8.4 中,现在自动管理了可用空间映射,消除了不再必要的调整参数,并消除了表膨胀的主要来源。

如果自动清理不足以使您的表和索引保持无膨胀状态,请调整它,不要用手动清理和重新索引来补充它。您可能需要增加可用空间映射设置(8.4 之前),调整自动清理使其更频繁地运行,或者告诉自动清理更积极地清理某些经常更新的表。

VACUUM

除非您需要将空间返回给操作系统,以便其他表或系统的其他部分可以使用该空间,或者您试图修复因自动清理不足而膨胀失控的表,否则您应该使用 VACUUM 而不是 VACUUM FULL

如果您需要在运行主要管理或更新任务(这些任务会重写表的大部分内容)以外的任何时间手动 VACUUM 您的表,那么您可能没有很好地设置自动清理。

CLUSTER

如果您试图通过压缩它们并删除因(例如)自动清理不够积极而累积的表膨胀来“优化”您的表,或者您试图将表中的死空间返回给操作系统,那么在 PostgreSQL 9.0 及更高版本中使用 VACUUM FULL 就可以了。

考虑设置 FILLFACTOR 低于默认值 100,这样重写的表将预先分配一些可用空间以用于更新和新插入;否则,只要您对表执行任何操作,就会得到文件系统分配。

在旧版本中,最好使用 CLUSTER。它比 9.0 之前的 VACUUM FULL 运行快得多,并且会压缩和优化索引以及它本身的表。但是,您需要有足够的空间来容纳来自表的全部使用中数据,才能让 CLUSTER 运行。与 9.0 之后的 VACUUM FULL 一样,非默认 FILLFACTOR 可能很明智。

TRUNCATE TABLE

如果您一直使用 VACUUM FULL 来释放来自一个表的空间,该表会定期使用 DELETE FROM tablename;(没有 WHERE 子句)完全清空,那么您可以使用 TRUNCATE TABLE 将这两个步骤替换为一个更快得多的步骤。

不要写

DELETE FROM tablename;
VACUUM FULL tablename;

TRUNCATE TABLE tablename;

请确保阅读 TRUNCATE TABLE 文档中的注意事项。如果 TRUNCATE TABLE 不适合您的需求,您可以使用 DELETE 然后是 CLUSTER 来代替。

如果在要进行外键引用的表上使用 DELETE,请考虑为引用列添加索引。这将允许检查外键强制执行,从而避免对引用表进行顺序扫描,使从被引用表中 DELETE 变得快得多。

ALTER TABLE .. SET DATA TYPE(仅适用于 8.4 及更低版本)

此部分已在 PostgreSQL 9.0 及更高版本中过时。除非您使用非常旧的版本,否则请跳过它。

CLUSTER 的问题在于它会按照索引的顺序重新排序表。如果表还没有接近该索引的顺序,这将花费很长时间,因为它必须多次对表页进行分散读取,因为它在寻找每个元组。一个更快的替代方法是请求完全表重写,而不需要特定的顺序。9.0 之前的 PostgreSQL 版本没有提供任何直接的方法来调用此操作;但是,您可以使用以下变通方法。选择任何表列,并使用 ALTER TABLE 将其类型更改为相同类型。这显然不会对表造成任何逻辑更改,但服务器将不得不重写表,并在此过程中消除死元组。

例如,假设 an_integer_column 的类型为 INTEGER

ALTER TABLE your_table ALTER an_integer_column SET DATA TYPE integer;

此技巧在 PostgreSQL 9.1 或更高版本中将不起作用,因为它会检测到数据类型的更改是退化的,因此不需要重写。

SELECT ... INTO(仅适用于 8.4 及更低版本)

此部分已在 PostgreSQL 9.0 及更高版本中过时。除非您使用非常旧的版本,否则请跳过它。

有时,使用 SELECT ... INTO 命令将数据从膨胀的表复制到新表,然后重新创建索引,最后重命名表以用新表替换旧表,可能会更快。但是,很少值得这样做,而不是使用 CLUSTER,因为 CLUSTER 几乎自动地做了同样的事情,并且可以并行重建索引。您可能想要使用 SELECT ... INTO 而不是 CLUSTER 的主要原因是,如果您不想对表进行排序。


VACUUM FULL 导致的索引膨胀中恢复(仅适用于 8.4 及更低版本)

此部分已在 PostgreSQL 9.0 及更高版本中过时。除非您使用非常旧的版本,否则请跳过它。

如果你的索引因频繁使用 VACUUM FULL 而过度膨胀,通常最好的解决方法是使用 CLUSTER 重写表格并重建索引。

如果你无法承受长时间的表格锁定,你可以单独重建每个索引,同时查询仍在表格上运行。不幸的是,PostgreSQL 并没有 REINDEX CONCURRENTLY 命令,但可以通过适当使用 CREATE INDEX ... CONCURRENTLYALTER INDEX ... RENAMEDROP INDEX 来模拟它。创建新的索引,通过重命名交换旧索引和新索引,然后删除旧索引。请注意,由于你无法删除某些索引,例如主键,因此这可能不是所有索引的有效清理方法。

最初由 --Ringerc 2009 年 11 月 26 日 03:48 (UTC) 撰写