当清理操作无法跟上针对表的数据操纵语言 (DML) 操作的速率时,就会出现表和索引膨胀。有些表和索引膨胀是不可避免的,并且通常可以接受,因为事务可以重复使用该空间。严重膨胀会导致性能问题,例如查询时间变长、I/O 增加、共享缓冲区和缓存使用效率降低,以及存储费用增加。
估算内存膨胀的最佳方法是使用 pgstattuple 模块。不过,当扩展程序必须读取关系的所有页面时,使用 pgstattuple 的效率会降低。如果您无法使用 pgstattuple,可以使用其他脚本来估算膨胀,不过这种方法的准确性较低。
读取 pgstattuple 输出
当您使用 pgstattuple 报告表或索引的物理存储特征时,输出采用以下格式:
> SELECT * FROM pgstattuple('large_table');
-[ RECORD 1 ]------+-----------
table_len | 7431888896
tuple_count | 66666666
tuple_len | 2796296271
tuple_percent | 37.63
dead_tuple_count | 0
dead_tuple_len | 0
dead_tuple_percent | 0
free_space | 3873153652
free_percent | 52.12
以下内容介绍了输出:
table_len(7431888896)- 表的大小总计(以字节为单位)。它包括所有活动元组、死元组和可用空间。在本例中,
large_table大约占用 7,088 GB。 tuple_count(66666666)- 表示表中的有效元组(即可见且活跃的行)数量。该表包含大约 6,600 万个有效行。
tuple_len(2796296271)- 所有实时元组的总长度(以字节为单位),约为 2.6 GB。
tuple_percent(37.63)活跃元组占
table_len的百分比。计算方法如下:(
tuple_len/table_len) ∗ 100 = (2796296271/7431888896) ∗ 100 ≈37.63%此输出表明,活跃数据使用的磁盘空间不到表的 40%。
dead_tuple_count(0)无效元组的数量 - 在更新或删除后,清理操作尚未移除的行。值为
0表示相应表是干净的,没有等待回收的无效元组。这通常表明VACUUM(即自动清理)在表上高效运行。dead_tuple_len(0)所有无效元组的总长度(以字节为单位)。与
dead_tuple_count一致,值为0表示失效行不占用任何空间。dead_tuple_percent(0)不活跃元组所占的
table_len百分比。计算方法如下:(
dead_tuple_len/table_len) ∗ 100 = (0/7431888896) ∗ 100 =0%free_space(3873153652)此值表示表数据页中的可用空间量。您可以将此空间重新用于新的插入或更新,而无需扩展表。这表示有大量可用空间,约为 3.7 GB。
free_percent(52.12)此值表示
table_len的可用空间百分比。 计算方式如下:(
free_space/table_len) ∗ 100 = (3873153652/7431888896) ∗ 100 ≈52.12%
使用查询估算膨胀
您可以通过针对系统目录表运行查询来估算膨胀,不过此方法不如使用 pgstattuple 等扩展程序准确。如果您使用 PostgreSQL 表膨胀检查等脚本,则表统计信息必须是最新的,否则估计值不准确。
将查询的输出与 pgstattuple 模块进行比较时,估计值具有可比性,但并非膨胀的确切测量值。该模块仍然是衡量膨胀程度的更准确指标,因为 SQL 查询依赖于 PostgreSQL 的累积统计信息引擎,而该模块读取的是实际数据页。
以下示例比较了两种不同的 PostgreSQL 表膨胀分析方法针对名为 large_table 的表的输出。
> SELECT * FROM pgstattuple('large_table');
-[ RECORD 1 ]------+-----------
table_len | 2475892736
tuple_count | 22000000
tuple_len | 922925931
tuple_percent | 37.28
dead_tuple_count | 0
dead_tuple_len | 0
dead_tuple_percent | 0
free_space | 1293696900
free_percent | 52.25
Vs.
-[ RECORD 1 ]+------------
databasename | postgres
schemaname | public
tablename | large_table
can_estimate | t
est_rows | 21965400
pct_bloat | 54
mb_bloat | 1269.24
table_mb | 2361.195
地址膨胀
您可以通过以下方式管理膨胀,每种方式都有其优点和缺点,需要仔细规划:
- 执行全面吸尘。此操作需要在清理期间锁定整个表,并且需要停机。
- 将数据移至新表。若要使用此方法,您必须使表更改静止,以确保更改不会转移到新关系。
- 使用
pg_squeeze。此扩展程序可缓解在线膨胀问题。该扩展程序会创建一个影子表,插入所有数据,然后使用复制槽维护表更改,直到最后一步,即用新创建的未膨胀的表替换膨胀的表。然后,它会请求一个简短的表锁定,以移动非膨胀表来替换膨胀表。此方法在操作期间需要两倍于对象的空间,但对正常操作的干扰最小。