PostgreSQL 数据文件的大小大于数据本身

3bd*_*lla 7 postgresql storage

我们有一个系统可以将一些数据归档到 PostgreSQL 数据库。我们发现由于数据库归档,PC 存储空间已满。问题是我检查了驻留在其中的数据文件/var/lib/pgsql/data/base/,它们总共大约 70 GB,而当我使用pg_dump输出文件转储所有数据库时,它们没有超过 24 GB。我在这里遗漏了什么或误解了什么?这么大的尺寸差异去哪儿了?

编辑:我确实pg_dump包含模式和数据,并带有-c允许删除和创建的选项。

编辑 2:我调查了 DB 模式文件,发现包含 24 GB(约 3.324 亿行)数据中的近 23.9 GB 的表上有一个索引。另一个表上有另一个索引,但该表为空。

编辑 3:程序定期存储大约 1500 个变量的值,我的意思是所有变量的记录时间为 0.1 秒到 1 分钟或更长时间,所以我认为这里有一个巨大的数据库访问。

编辑 4:我在这里执行第二个查询以查找模式中每个关系的大小,我发现以下内容:

  • 28 GB 用于主数据表。
  • 大约 42 GB 仅用于 3 个索引!24、9、9。

我的目的是我想经常(每隔几个月)进行一次备份和恢复。在进行备份和恢复时,我应该关心这些数据库索引还是只关注我的数据表?

hru*_*ske 12

由于以下几个原因,尺寸可能会有所不同:

  • 索引占用一些磁盘空间,
  • 磁盘上可以有多个相同记录的副本,
  • 页中的松弛空间。

索引占用磁盘空间以促进更快的查找。您拥有的索引越多,您的数据库占用的磁盘空间就越多。GIN 索引通常较小,但在使用范围查询时没有用。

PostgreSQL 支持并发访问,它的实现方式是,对记录的更新和删除只会改变记录的可见性,而不会实际删除或覆盖数据,因为一个记录可能会被另一个事务使用。通过更新,然后添加一个新的(更新的)副本。两者都意味着旧数据仍写入磁盘。为了释放它,PostgreSQL 会定期执行清理,这会真正删除已删除的记录(在没有事务使用它们之后)。

PostgreSQL 的默认块大小为 8KB。如果你的记录很大,比如 5KB,你只能在一个块中得到一条记录,有相当大的 (~3KB) slack。

一些可能的解决方案是:

  • 一定要知道如何在 PostgreSQL 中检查磁盘使用情况
  • 重新评估您是否真的需要所有索引,
  • 想想你的数据访问模式是什么 - 如果它只是附加表,那么不可见的记录应该很少。另一方面,如果您的数据更改了一段时间并在一段时间后存档,则可能会引用多个记录在磁盘上。如果是这种情况,那么对表进行分区可能会有所帮助,因为您可以单独对分区进行真空分区。
  • 你可以手动吸尘表。不要使用 VACUUM FULL,因为它将写入表的新副本并需要适当数量的磁盘空间。
  • 您可以使用一些在线(在线,因为您不需要关闭数据库)重新打包工具,例如pg_repack

编辑:

pg_dump

pg_dump 没问题,如果您指定转储数据,正如您所说的那样。如果您使用自定义格式(-Fc 标志),pg_restore 将能够用它做一些额外的事情,例如只加载指定的表,另见 pg_dump 的手册页。默认情况下自定义格式 gzip 转储。这可能会减慢您的转储速度,因此您可能希望禁用它,如果您仍希望对数据进行 gzip,则可以使用并行 gzip (pigz)。

备份

备份时,您备份表中的数据。从表中的数据重新创建索引。如果您在进行备份和恢复时能够承受数据库的大量 IO,那么 pg_dump 和 pg_restore 可能适合您的需求。转储时,pg_dump 仅转储表,而在恢复时,索引会作为恢复的一部分自动重建。所以要说清楚:备份不关心索引。

如果大量 IO 和性能下降是不可接受的,那么您可能希望拥有一个辅助复制服务器,它将拥有数据副本,但不会为您的普通查询提供服务,因此您可以使用它进行转储。

如果您需要时间点恢复功能,您可以设置 WAL 日志(预写日志)归档,然后您可以恢复到特定事务​​,但这是非常先进的。有一些工具可以提供帮助,例如Barman

大索引

正如您已经发现的那样,索引会占用大量空间。如果您将数据和索引相加,您的数据库大小为:28GB + 42GB = 70GB。

拥有大索引意味着使用了大量额外的磁盘空间。索引数据也缓存在内存中,因此拥有大索引意味着您可能在 RAM 中有两个索引数据副本,这意味着用于在磁盘上缓存数据的 RAM 更少,并且您会遇到更多缓存未命中。有一些选项可以评估以缩小索引:

  • 部分索引:如果应用程序只查询将 one 字段设置为特定值的位置,您可以使用 CREATE INDEX 上的 WHERE 子句限制索引哪些行。
  • 使用索引扫描:如果可以将所有查询到的数据都包含在一个索引中,那么 PostgreSQL 可以只读取索引数据来返回。从 PostgreSQL 9.2 开始工作,在 wiki 上查看有关索引扫描的更多信息。
  • 使用另一种类型的索引:如果您的应用程序仅执行相等查找(WHERE a = 4),则 GIN 索引可以小得多,请参阅btree_gin 扩展。PostgreSQL 9.5 还将带来 BRIN 索引,这对于具有单调递增或递减模式的字段非常有用,例如时间戳,而且它们非常小,因此您可以释放磁盘空间用于更多存储和 RAM 用于缓存更多数据。

但是……这在很大程度上取决于数据的访问方式,这通常只有应用程序的开发人员知道。


Bua*_*aXD 3

pg_dump 仅包含重新创建数据库所需的 SQL 语句。

实际的数据文件包含您插入的数据和所有其他数据库对象,特别是索引:聚集索引(数据本身)和非聚集索引:按指定键排序的选定列。

pd_dump 包含 CREATE INDEX 语句,数据文件包含索引本身(它可能非常大)。