SQL COMMAND · 其它对象
REPACK
重写表以回收磁盘空间
rewrite a table to reclaim disk space
REPACK其它对象引入 19现存至 20 devel0 次语法变更
- 动词
REPACK- 对象
—- 分组
- 其它对象
- 引入版本
- 19
- 状态
- 现存
- 语法变更次数
- 0
- 手册小节数
- 6
版本轨迹
相对 PostgreSQL 19 无变化。
PostgreSQL 20 devel 尚未正式发布;本页来自对应手册快照,内容仍可能变化。
语法铁道图 PostgreSQL 20
沿轨道从左向右阅读,分岔表示选择,绕行表示可选,回环表示重复。方框为参数,点击带下划线的参数可展开子规则。
REPACK · 语法 2
option
table_and_columns
锁模式 PostgreSQL 20
具体锁模式取决于操作变体、目标对象和执行阶段;同一命令可同时取得表锁与行锁。查看完整冲突矩阵
SHARE UPDATE EXCLUSIVE· 表级锁REPACK (CONCURRENTLY)(复制与追赶阶段):PostgreSQL 19 起;主体阶段在目标表上持有 SHARE UPDATE EXCLUSIVE,切换文件阶段再升级为 ACCESS EXCLUSIVE。ACCESS EXCLUSIVE· 表级锁REPACK(不含 CONCURRENTLY):PostgreSQL 19 起;整个重写期间在目标表上取得 ACCESS EXCLUSIVE。REPACK (CONCURRENTLY)(切换文件阶段):PostgreSQL 19 起;主体复制允许并发读写,最终切换表与索引文件时取得 ACCESS EXCLUSIVE;等待后补放的变更可能延长该阶段。
语法概要
REPACK [ ( option [, ...] ) ] [ table_and_columns [ USING INDEX [ index_name ] ] ] REPACK [ ( option [, ...] ) ] USING INDEX 其中 option 可以是以下之一: VERBOSE [ boolean ] ANALYZE [ boolean ] CONCURRENTLY [ boolean ] 而 table_and_columns 为: table_name [ ( column_name [, ...] ) ]
描述
REPACK 可回收被死元组占用的存储空间。与 VACUUM 不同,它通过将
table_name 所指定表的全部内容重写到一个没有多余空间的新磁盘文件中来实现这一点(fillfactor 存储参数所保证的空间除外),从而允许未使用的空间返回给操作系统。
如果没有指定 table_name,REPACK 会处理当前数据库中当前用户具有
MAINTAIN 特权的每一张表和物化视图。此形式的 REPACK 不能在事务块中执行。如果使用了 CONCURRENTLY 选项,则也不允许使用这种形式。
如果指定了 USING INDEX 子句,行会根据索引中的信息在物理上重新排序。请参见下文的 Notes on Clustering。
当对一个表执行重整时,除非指定了 CONCURRENTLY 选项,否则会在该表上获取 ACCESS EXCLUSIVE 锁。有关该选项效果的讨论,请参见 Notes on Concurrent Operation。
参数
table_name表的名称(可以带模式限定)。
column_name要分析的特定列名称。默认是所有列。如果指定了列列表,则还必须同时指定
ANALYZE。index_name索引的名称。
CONCURRENTLY允许其他事务在重整期间使用该表。更多详细信息请参见 Notes on Concurrent Operation。
VERBOSE以
INFO级别打印每个表被重整时的进度报告。ANALYZEANALYSE在重整表之后对该表执行 ANALYZE。目前这只在指定单个(非分区)表时受支持。此选项不能在事务块内使用,也不能从函数、过程或
DO块中使用。boolean指定所选选项应开启还是关闭。可以写
TRUE、ON或1来启用该选项,也可以写FALSE、OFF或0来禁用它。boolean值也可以省略,此时默认视为TRUE。
说明
要重整表,必须对该表具有 MAINTAIN 特权。
REPACK 主要用于消除膨胀,并在使用 USING INDEX 时对表进行聚簇,以提高性能。虽然它也会推进表的 relfrozenxid 和 relminmxid,但它并不适合用来防止事务 ID 或多事务 ID 回卷:它会重写整个表及其所有索引,因此比 VACUUM 耗时长得多,而且可能在大部分工作完成后失败,尤其是在繁忙的表上使用 CONCURRENTLY 时。建议使用 VACUUM 来防止回卷(见第 24.1.5 节)。当表接近回卷时,VACUUM 会自行跳过索引清理(见 vacuum_failsafe_age),而其 INDEX_CLEANUP OFF 选项可以提前实现同样的效果。
REPACK 拒绝处理存在无效索引的表。这类索引必须由用户提前删除或重建。
在 REPACK 运行期间,search_path 会临时改为 pg_catalog, pg_temp。
每个运行 REPACK 的后端都会在 pg_stat_progress_repack 视图中报告其进度。有关详细信息,请参见第 27.4.5 节。
重整分区表时,会重整其每个分区。如果指定了索引,则每个分区都会使用该索引的分区来重整。对分区表执行 REPACK 不能在事务块中进行。
聚簇说明
如果指定了 USING INDEX 子句,表中的行会按指定索引隐含的顺序在物理上重新排列,这称为聚簇。这可能影响性能:如果是在表内随机访问单行,那么表中数据的实际顺序并不重要。但如果更频繁地访问某些数据,并且有一个能把它们聚集在一起的索引,就能从聚簇中受益。如果从表中请求一个索引值范围,或者请求一个匹配多行的单个索引值,聚簇也会有所帮助,因为一旦索引确定了第一个匹配行所在的表页,其他匹配行很可能已经在同一个表页上,从而节省磁盘访问并加快查询。
对于 B-树索引,聚簇使用索引的线性排序顺序。其他支持聚簇的索引访问方法可能使用不同的排序策略,这种策略不一定对应任何 SQL 排序顺序。如果命令中指定了索引名,则使用该索引,并将其记录为该表的聚簇索引。(这同样适用于传给 CLUSTER 命令的索引。)如果未指定索引名,则使用已经被配置为聚簇索引的索引;如果没有这样的索引,就会报错。可以使用 ALTER TABLE ... CLUSTER ON 手工设置索引,也可以使用
ALTER TABLE ... SET WITHOUT CLUSTER 清除设置。
聚簇是一次性操作:表随后被更新时,这些更改不会继续保持聚簇。也就是说,并不会尝试根据聚簇顺序存储新行或更新后的行。(如果愿意,可以通过再次发出该命令来定期重新聚簇。此外,把表的 fillfactor
存储参数设置为低于 100%,有助于在更新期间保持聚簇顺序,因为如果页面上有足够空间,更新后的行会保留在同一页面上。)
在 B-树索引上聚簇时,REPACK 可以通过在指定索引上进行索引扫描,或者先执行顺序扫描再排序,来重写表。它会根据规划器代价参数和可用的统计信息,尝试选择速度更快的方法。在使用 B-树以外的访问方法的索引上聚簇时,REPACK 始终使用索引扫描。
因为规划器会记录有关表中数据顺序的统计信息,建议指定 ANALYZE 选项,或者在新近重整过的表上运行 ANALYZE。否则,规划器可能会选择很差的查询计划。
如果在 REPACK USING INDEX 中没有指定表名,那么所有已经定义了聚簇索引、且调用用户具有相应权限的表都会被处理。
资源说明
REPACK 会创建表及其所有索引的临时副本,因此需要至少等于表大小与索引大小之和的磁盘可用空间。
如果指定了 USING INDEX 子句,且规划器选择通过顺序扫描加排序来实现,那么除了上述空间之外,还需要一个最大可达表大小的临时排序文件。这种方法通常比索引扫描更快,但如果磁盘空间要求无法接受,可以通过临时将 enable_sort 设为 off 来禁用这种选择;如果不需要重新排序表,也可以省略 USING INDEX。
就事务 ID 回卷而言(见第 24.1.5 节),REPACK 被视为一个长时间运行的事务,会阻止 VACUUM 清理其他表中的死行。在重整非常大的表时,建议监控运行 REPACK 的进程的 pg_stat_activity.backend_xid,以免导致其他表过度膨胀。
建议在重整之前,将 maintenance_work_mem 设置为一个相当大的值(但不要超过你可为 REPACK
操作预留的内存总量)。
并发操作说明
警告
带 CONCURRENTLY 选项的 REPACK 不是 MVCC 安全的。重整事务提交后,如果并发事务使用的是重整开始之前取得的快照,该表在这些事务看来将是空的。更多详细信息请参见第 13.6 节。
REPACK 会把表内容(忽略死元组)复制到一个新文件中,并按指定索引排序,同时还会为每个索引创建一个新文件。然后它交换表及其所有索引的旧文件和新文件,并删除旧文件。不使用 CONCURRENTLY 选项时,会在开始时获取 ACCESS EXCLUSIVE 锁,并在整个操作期间持续持有,以确保处理过程中旧文件不会变化;否则,任何并发更改都会因交换而丢失。
相比之下,指定 CONCURRENTLY 选项时,大部分操作在持有 SHARE UPDATE EXCLUSIVE 锁的情况下执行,只有在交换表文件和索引文件的最后阶段才会获取 ACCESS EXCLUSIVE 锁。在创建新表和索引文件期间发生的数据更改会通过逻辑解码(见第 47 章)捕获,并在请求 ACCESS EXCLUSIVE 锁之前应用。获取该锁后,会对捕获的剩余并发数据更改做最后一轮处理,然后交换文件。因此,该锁通常只会持有很短的时间,具体取决于等待锁期间积累的更改量。
处理这些并发更改时,每个被并发更新或删除的元组都需要占用少量固定大小的内存,这部分内存不受 maintenance_work_mem 限制;如果在 REPACK 执行期间被并发更新或删除的行超过大约 1.04 亿,命令就会失败。此外,所有并发更改的完整元组数据(未被 UPDATE 修改的 TOAST 列除外)都会单独存储在磁盘上。
如果其他事务在重整期间对该表执行 DDL 命令,REPACK (CONCURRENTLY) 可能无法完成。
REPACK (CONCURRENTLY) USING INDEX 不会尝试对重整开始之后插入到表中的行进行排序。
CONCURRENTLY 选项不能在以下情况下使用:
该关系不是表(例如,它是物化视图)。
该表是
UNLOGGED。该表是分区表。
该表没有主键,也没有基于索引的复制标识。
该表是系统目录或 TOAST 表。
该表的访问方法不是
heap。该表通过
user_catalog_table存储参数被声明为目录表。REPACK在事务块中执行。max_repack_replication_slots配置参数不允许再创建一个额外的复制槽。
示例
重整表 employees:
REPACK employees;
基于其索引 employees_ind 重整表 employees(由于指定了索引,这实际上就是聚簇):
REPACK employees USING INDEX employees_ind;
以并发模式使用与之前相同的索引重整 employees 表:
REPACK (CONCURRENTLY) employees USING INDEX;
按物理顺序重整表 cases,在重整完成后对给定列执行 ANALYZE,并显示信息消息:
REPACK (ANALYZE, VERBOSE) cases (district, case_nr);
重整数据库中所有你具有 MAINTAIN 特权的表:
REPACK;
重整所有此前已配置聚簇索引、且你具有 MAINTAIN 特权的表,并显示信息消息:
REPACK (VERBOSE) USING INDEX;
兼容性
SQL 标准中没有 REPACK 语句。
另见
语法演化
相邻大版本之间的差异,新的在前。版本号链接到对应快照。
PostgreSQL 19← 18新增此命令
同组命令
| 命令 | 动词 | 对象 | 版本变动 | 最近变更 |
|---|---|---|---|---|
COMMENT | COMMENT | — | 1115 次 | |
| 定义或修改对象的注释 | 现存 | |||
REPACK | REPACK | — | — | |
| 重写表以回收磁盘空间 | 现存 | |||
ALTER LARGE OBJECT | ALTER | LARGE OBJECT | 142 次 | |
| 更改一个大对象的定义 | 现存 | |||