Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17

14.4 填充数据库 #

14.4.1 禁用自动提交
14.4.2 使用 COPY
14.4.3 删除索引
14.4.4 删除外键约束
14.4.5 增加 maintenance_work_mem
14.4.6 增加 max_wal_size
14.4.7 禁用 WAL 归档和流复制
14.4.8 之后运行 ANALYZE
14.4.9 关于 pg_dump 的一些注意事项

首次填充数据库时可能需要插入海量数据。本部分提供一些建议,说明如何尽可能有效地完成此过程。

14.4.1 禁用自动提交 #

使用多个 INSERT 时,关闭自动提交,并在最后只提交一次。(在普通 SQL 中,这意味着在开始时发出 BEGIN,在结束时发出 COMMIT。某些客户端库可能在您不知情的情况下执行此操作,在这种情况下,您需要确保库在您希望其执行此操作时执行此操作。)如果您允许每次插入操作单独提交,PostgreSQL 就会为添加的每行执行大量工作。一次性在单事务中执行所有插入操作的另一个好处是,如果某一行插入失败,那么之前插入的所有行都会回滚,因此您不会被部分加载的数据困住。

14.4.2 使用 COPY #

使用 COPY 在一个命令中加载所有行,而不是使用一系列 INSERT 命令。COPY 命令针对加载大量行进行了优化;它没有 INSERT 那么灵活,但在加载大量数据时产生的开销会大大降低。由于 COPY 是一个单独的命令,如果您使用此方法填充表格,则无需禁用自动提交。

如果您无法使用 COPY,那么使用 PREPARE 创建准备好的 INSERT 语句,然后按需多次使用 EXECUTE 可能会有帮助。这避免了重复分析和规划 INSERT 带来的一些开销。不同的接口以不同的方式提供此功能;在接口文档中查找 准备好的语句

请注意,使用 COPY 加载大量行几乎总是比使用 INSERT 更快,即使使用了 PREPARE 并且多个插入被批处理到单个事务中也是如此。

当与先前的 CREATE TABLETRUNCATE 命令在同一事务中使用时,COPY 最快。在这种情况下,无需写入 WAL,因为如果出现错误,将删除包含新加载数据的文件。但是,只有在 wal_levelminimal 时,这种考虑才适用,因为否则所有命令都必须写入 WAL。

14.4.3. 删除索引 #

如果您正在加载新创建的表,最快的办法是创建表、使用 COPY 批量加载表的数据,然后创建表所需的任何索引。在预先存在的数据上创建索引比在加载每一行时对其进行增量更新更快。

如果您正在向现有表中添加大量数据,删除索引、加载表,然后重新创建索引可能会有好处。当然,在这个索引缺失的时间段内,其他用户的数据库性能可能会受到影响。在删除唯一索引之前,还应三思,因为在索引缺失期间将失去唯一约束提供的错误检查。

14.4.4. 删除外键约束 #

与索引一样,外键约束也可以比逐行检查更有效地检查 批量。因此,丢弃外键约束、加载数据并重新创建约束可能很有用。同样,在约束缺失期间,数据加载速度和错误检查的损失之间存在一个权衡。

此外,当您将数据加载到具有现有外键约束的表中时,每一行都需要服务器的待处理触发器事件列表中的一个条目(因为触发器检查行的外键约束)。加载数百万行会导致触发器事件队列溢出可用内存,从而导致无法忍受的交换甚至命令彻底失败。因此,当加载大量数据时,删除并重新应用外键可能不仅仅是可取的,而是必要的。如果暂时删除该约束不可行,唯一其他办法可能是将加载操作拆分为较小的事务。

14.4.5. 增大 maintenance_work_mem #

加载大量数据时,可以临时增加 maintenance_work_mem 配置变量来提高性能。这将有助于加快 CREATE INDEX 命令和 ALTER TABLE ADD FOREIGN KEY 命令的速度。这对于 COPY 自身的影响不大,因此此建议仅在使用上述一种或两种技术时才有用。

14.4.6. 增加 max_wal_size #

临时增加 max_wal_size 配置变量也可以加快大量数据加载。这是因为将大量数据加载到 PostgreSQL 中会导致检查点比正常检查点频率(由 checkpoint_timeout 配置变量指定)更频繁地发生。每当检查点发生时,所有脏页面都必须刷新到磁盘。通过在批量数据加载期间临时增加 max_wal_size,可以减少所需的检查点数。

14.4.7. 禁用 WAL 存档和流复制 #

在加载大量数据到使用 WAL 存档或流复制的安装中时,加载完成后进行一次新基准备份可能比处理大量增量 WAL 数据更快。要防止在加载时进行增量 WAL 日志记录,请通过将 wal_level 设置为 minimalarchive_mode 设置为 off 以及 max_wal_senders 设置为零来禁用存档和流复制。但请注意,更改这些设置需要重新启动服务器,并且会使在以前采取的任何基准备份在存档恢复和备用服务器中不可用,这可能导致数据丢失。

除了可以避免存档器或 WAL 发件人处理 WAL 数据的时间外,这样做实际上会使某些命令更快,这是因为如果 wal_levelminimal 并且当前子事务(或顶层事务)创建或截断了它们更改的表或索引,则它们根本不需要写入 WAL。(在结尾处执行 fsync 比写入 WAL 更便宜,可以确保崩溃安全性。)

14.4.8. 事后运行 ANALYZE #

每当显著改变表格中的数据分布时,强烈建议运行 ANALYZE。这包括向表格中批量加载大量数据。运行 ANALYZE(或 VACUUM ANALYZE)确保规划器具备关于该表的最新统计信息。如果没有统计信息或统计信息已过时,则规划器在查询计划期间可能会做出错误的决策,从而导致任何具不准确或不存在统计信息的表格性能不佳。请注意,如果自动真空守护进程已启用,则它可能会自动运行 ANALYZE;请参阅 部分 24.1.3部分 24.1.6 了解更多信息。

14.4.9. pg_dump 的一些注意事项 #

pg_dump 生成的数据转储脚本会自动应用上述部分指南,但并非全部。要尽可能以最快速度还原 pg_dump 数据转储,你需要手动执行一些操作。(请注意,这些要点适用于 恢复 数据转储,而不适用于 创建 数据转储。无论使用 psql 加载文本数据转储还是使用 pg_restorepg_dump 存档文件加载,都适用相同的要点。)

默认情况下,pg_dump 使用 COPY,在生成完整的架构和数据转储时,它会在创建索引和外键前谨慎地加载数据。因此,在此情况下,会自动处理几项指南。剩下的操作由你完成,包括

  • 设置 maintenance_work_memmax_wal_size 的适当值(即大于正常值)。

  • 如果在还原期间使用 WAL 存档或流复制,请考虑将其禁用。要执行此操作,请在加载数据转储之前将 archive_mode 设置为 off,将 wal_level 设置为 minimal,并将 max_wal_senders 设置为零。之后,将它们设回正确的数值并执行新鲜的基础备份。

  • 尝试使用 pg_dumppg_restore 的并行数据转储和还原模式,并找出要使用的最佳并发作业数。通过选项 -j 并行数据转储和还原应在串行模式中大幅提升性能。

  • 考虑是否应将整个转储还原为单个事务。若要实现该目的,需将 -1--single-transaction 命令行选项传递给 psqlpg_restore。使用此模式时,即便是最小的错误也会回滚整个还原,可能丢弃许多小时的处理。根据数据有何相互联系,这种情况看起来可能比手动清理好,或不好。如果您使用单个事务并已关闭 WAL 存档,COPY 命令运行得最快。

  • 如果数据库服务器有多个 CPU 可用,请考虑使用 pg_restore--jobs 选项。这将允许并发数据加载和索引创建。

  • 之后运行 ANALYZE

仅限数据转储仍将使用 COPY,但它不删除或重新创建索引,并且通常不会接触外键。[14] 因此,在加载仅限数据转储时,如果您想使用那些技术,则需要删除和重新创建索引和外键。在加载数据时,增加 max_wal_size 仍很有帮助,但不要费心增加 maintenance_work_mem;相反,您可以在之后手动重新创建索引和外键时再执行此操作。并且不要忘记,完成后进行 ANALYZE;有关更多信息,请参见24.1.3 节24.1.6 节



[14] 您可以使用 --disable-triggers 选项来禁用外键,但请意识到这会消除外键验证,而不是仅仅将其延期,因此,如果使用它就可能会插入错误数据。