↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1
历史版本PostgreSQL 8.4 已于 2014 年 7 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本。

14.4. 填充一个数据库 #

初次填充数据库时,可能需要插入大量数据。本节给出一些使这一过程尽可能高效的建议。

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,并把多次插入批量放入同一个事务中也是如此。

当COPY与更早的CREATE TABLE或TRUNCATE命令处于同一事务中时,速度最快。在这种情况下,不需要写 WAL,因为一旦出错,包含新装载数据的文件反正也会被移除。不过,当archive_mode开启时这一点并不适用,因为在这种情况下所有命令都必须写 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. 增加checkpoint_segments #

临时增大checkpoint_segments配置变量,也可以让大规模数据装载更快。这是因为向PostgreSQL中装载大量数据,会导致检查点比平常更频繁地发生,而正常频率由checkpoint_timeout配置变量指定。每次发生检查点时,所有脏页都必须刷写到磁盘。通过在批量装载期间临时增大checkpoint_segments,可以减少所需的检查点次数。

14.4.7. 关闭archive_mode #

当向使用 WAL 归档的安装中载入大量数据时,你可能希望在装载期间禁用归档(关闭archive_mode配置变量)。完成装载后重新做一次基础备份,可能比处理大量增量 WAL 数据更快。但请注意,打开或关闭archive_mode需要重启服务器。

这样做除了省去归档进程处理 WAL 数据的时间外,还能使某些命令执行得更快,因为这些命令被设计为在archive_mode关闭时完全不写 WAL。(它们可以在结束时执行一次fsync,以比写 WAL 更低的代价保证崩溃安全性。)这适用于以下命令:

  • CREATE TABLE AS SELECT

  • CREATE INDEX(以及 ALTER TABLE ADD PRIMARY KEY 等变体)

  • ALTER TABLE SET TABLESPACE

  • CLUSTER

  • COPY FROM,前提是目标表在同一事务中已被创建或截断

14.4.8. 事后运行ANALYZE #

每当显著改变了表中数据的分布,都强烈建议运行ANALYZE。这也包括向表中批量装载大量数据。运行ANALYZE(或VACUUM ANALYZE)可以确保规划器掌握该表的最新统计信息。如果没有统计信息,或者统计信息已经过时,规划器在生成查询计划时就可能做出糟糕决定,从而导致相关表性能不佳。注意,如果启用了自动清理守护进程,它可能会自动运行ANALYZE;详见更新规划器统计信息和自动清理守护进程。

14.4.9. 关于pg_dump的一些注记 #

由pg_dump生成的转储脚本会自动应用上面若干条指导原则,但并非全部。 若要尽可能快速地还原pg_dump的转储,仍需手动做一些额外操作。 (注意,这些要点适用于还原转储,而不是创建转储。 在使用pg_restore从pg_dump归档文件加载时,相关要点是一样的。)

默认情况下,pg_dump使用COPY;而当它生成完整的模式加数据转储时,也会小心地先装载数据,再创建索引和外键。因此在这种情况下,上述若干指导原则已经被自动处理。剩下需要做的是:

  • 为maintenance_work_mem和checkpoint_segments设置适当的(即比正常值大的)值。

  • 如果使用 WAL 归档,可以考虑在恢复期间禁用它。为此,请在载入转储脚本之前关闭archive_mode,恢复完成后再把它打开,并重新做一次基础备份。

  • 考虑是否应当把整个转储作为单个事务来恢复。要这样做,请把-1或--single-transaction命令行选项传给psql或pg_restore。使用这种模式时,即使是很小的错误也会回滚整个恢复过程,可能丢掉数小时的处理成果。视数据之间的关联程度而定,这种做法未必一定比手工清理更可取。如果使用单个事务并关闭 WAL 归档,COPY命令会运行得最快。

  • 之后运行ANALYZE。

仅包含数据的转储仍然会使用COPY,但它不会删除或重建索引,通常也不会处理外键。 [10] 因此,在装载纯数据转储时,如果想采用这些技术,就需要自行负责删除并重建索引与外键。装载数据期间增大checkpoint_segments仍然有益,但没有必要同时增大maintenance_work_mem;后者更适合留到之后手工重建索引和外键时再调大。完成后也别忘了执行ANALYZE;详见更新规划器统计信息和自动清理守护进程。



[10] 可以通过使用--disable-triggers选项达到禁用外键的效果 — 但要注意,这样做是取消外键验证,而不仅仅是推迟它。因此如果使用该选项,就有可能插入坏数据。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。