On this page
14.4. 填充数据库
首次填充数据库时,可能需要插入大量数据。本节包含有关如何使此过程尽可能高效的一些建议。
14 .4.1. 禁用自动提交
使用多个INSERT
时,请关闭自动提交功能,最后只进行一次提交。 (在普通的 SQL 中,这意味着在开始处发出BEGIN
,在末尾发出COMMIT
.某些 Client 端库可能在后台执行此操作,在这种情况下,您需要确保在需要时执行该操作.)如果允许每个插入分别提交,PostgreSQL 对添加的每一行都做了很多工作。在一个事务中进行所有插入的另一个好处是,如果一行的插入失败,那么将回滚到该点为止插入的所有行的插入,因此不会卡住部分加载的数据。
14 .4.2. 使用 COPY
使用COPY可以在一个命令中加载所有行,而不是使用一系列INSERT
命令。 COPY
命令已针对加载大量行进行了优化;它的灵 Active 不如INSERT
,但是对于大数据负载而言,开销却要少得多。由于COPY
是单个命令,因此如果使用此方法填充表,则无需禁用自动提交。
如果不能使用COPY
,则可以使用PREPARE创建准备好的INSERT
语句,然后根据需要使用EXECUTE
多次,这可能会有所帮助。这避免了重复解析和计划INSERT
的一些开销。不同的接口以不同的方式提供此功能。在界面文档中查找“准备好的语句”。
请注意,即使使用PREPARE
并且将多个插入批处理到单个事务中,使用COPY
加载大量行几乎总是比使用INSERT
更快。
在与较早的CREATE TABLE
或TRUNCATE
命令相同的事务中使用COPY
时最快。在这种情况下,无需写入 WAL,因为如果发生错误,则无论如何都将删除包含新加载的数据的文件。但是,这种考虑仅适用于非分区表的wal_level为minimal
的情况,因为所有命令否则都必须写入 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设置为minimal
,将archive_mode设置为off
并将max_wal_senders设置为零来禁用归档和流复制。但是请注意,更改这些设置需要重新启动服务器。
除了避免使归档程序或 WAL 发送者花费时间来处理 WAL 数据外,这样做实际上会使某些命令更快,因为如果wal_level
为minimal
,则它们根本不写 WAL。 (与编写 WAL 相比,通过在末尾执行fsync
可以更便宜地保证碰撞安全.)这适用于以下命令:
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
)可确保计划者拥有有关表的最新统计信息。没有统计信息或统计信息过时,规划器可能会在查询计划期间做出错误的决策,从而导致统计信息不正确或不存在的任何表的性能都较差。请注意,如果启用了 autovacuum 守护程序,则它可能会自动运行ANALYZE
;有关更多信息,请参见Section 24.1.3和Section 24.1.6。
14 .4.9. 关于 pg_dump 的一些注意事项
pg_dump 生成的转储脚本会自动应用上述准则中的一些,但不是全部。要尽快重新加载 pg_dump 转储,您需要手动做一些额外的事情。 (请注意,这些要点在“恢复”转储时适用,而不是在“创建”转储时适用.在使用 psql 加载文本转储或使用 pg_restore 从 pg_dump 存档文件中加载时,这些要点同样适用.)
默认情况下,pg_dump 使用COPY
,当它生成一个完整的模式和数据转储时,在创建索引和外键之前要小心加载数据。因此,在这种情况下,会自动处理一些准则。您要做的是:
为
maintenance_work_mem
和max_wal_size
设置适当的值(即大于正常值)。如果使用 WAL 归档或流复制,请考虑在还原过程中将其禁用。为此,在加载转储之前,将
archive_mode
设置为off
,将wal_level
设置为minimal
,并将max_wal_senders
设置为零。然后,将它们重新设置为正确的值,然后重新进行基本备份。对 pg_dump 和 pg_restore 的并行转储和还原模式进行试验,并找到要使用的最佳并行作业数。通过
-j
选项并行转储和还原应该比串行模式显着提高性能。考虑是否应将整个转储作为单个事务还原。为此,请将
-1
或--single-transaction
命令行选项传递给 psql 或 pg_restore。使用此模式时,即使最小的错误也将回滚整个还原,可能会丢弃许多小时的处理时间。根据数据之间的相互关系,这似乎比手动清理更可取。如果您使用单个事务并关闭 WAL 归档,则COPY
命令将以最快的速度运行。如果数据库服务器中有多个 CPU,请考虑使用 pg_restore 的
--jobs
选项。这允许并发数据加载和索引创建。之后运行
ANALYZE
。
仅数据转储仍将使用COPY
,但它不会删除或重新创建索引,并且通常不会触摸外键。 [12]因此,在加载仅数据转储时,如果您希望使用这些技术,则可以删除并重新创建索引和外键。在加载数据时增加max_wal_size
仍然很有用,但不要担心增加maintenance_work_mem
;相反,您会在之后手动重新创建索引和外键的同时这样做。完成后别忘了ANALYZE
;有关更多信息,请参见Section 24.1.3和Section 24.1.6。
[12]您可以使用--disable-triggers
选项获得禁用外键的效果-但要意识到,这消除了外键验证,而不仅仅是推迟外键验证,因此如果使用它,可以插入错误数据。