我们第一次填充数据库时可能需要做大量的表插入。 下面是一些建议,可以尽可能高效地处理这些事情。
关闭自动提交,并且只在每次(数据拷贝)结束的时候做一次提交。 (在纯 SQL 里,这就意味着在开始的时候发出 BEGIN, 并且在结束的时候执行 COMMIT。有些客户端的库可能背着你干这些事情, 这种情况下你必须确信只有在你要那些库干这些事情的时候它才做。) 如果你允许每个插入都独立地提交,那么 PostgreSQL 会为所增加的每行记录做大量的处理。 在一个事务里完成所有插入的动作的最大的好处就是,如果有一条记录插入失败, 那么,到该点为止的所有已插入记录都将被回滚,这样你就不会很难受地面对一个只装载了一部分数据的表。
使用 COPY 在一条命令里装载所有记录, 而不是一连串的INSERT命令。COPY 命令是为装载数量巨大的数据行优化过的; 它没 INSERT 那么灵活,但是在大量装载数据的情况下,导致的过荷也少很多。 因为 COPY 是单条命令,因此填充表的时候就没有必要关闭自动提交了。
如果你不能使用 COPY,那么 使用 PREPARE 来创建一个准备好的 INSERT, 然后使用 EXECUTE 多次效率更高。 这样就避免了重复分析和规划 INSERT 的开销。
请注意,在装载大量数据行的时候,COPY 几乎总是比 INSERT 快, 即使使用了 PREPARE 并且把多个 INSERT 命令绑在一个事务中也是这样的。
如果你正在装载一个新创建的表,最快的方法是创建表, 用COPY批量装载,然后创建表需要的任何索引。 在已存在数据的表上创建索引要比递增地更新所装载的每一行记录要快。
如果你对现有表进行增大操作,你可以删除索引, 装载表,然后重新创建索引。 当然,在缺少索引的期间,其他数据库用户的数据库性能将有负面的影响。 并且我们在删除唯一索引之前还需要仔细考虑清楚,因为唯一约束 提供的错误检查在缺少索引的时候会消失.
在装载大量的数据的时候,可以临时增大 maintenance_work_mem 配置变量以便改进性能。 这是因为在从零开始创建一个 B-tree 索引地时候,现有的表需要进行排序。 允许融合排序使用更多的缓冲页面意味着需要少一些的融合回合数。
临时增大 checkpoint_segments 配置变量也可以让大量数据装载得更快。 这是因为向 PostgreSQL 里面装载大量的数据可以导致检查点操作 (由配置变量 checkpoint_timeout 声明) 比平常更加频繁发生。在发生一个检查点的时候,所有脏数据都必须刷新到磁盘上。 通过在大量数据装载的时候临时增加 checkpoint_segments, 所要求的检查点的数目可以减少。
不管甚么时候,如果你在增加或者更新了大量数据之后, 运行 ANALYZE 都是个好习惯。 运行 ANALYZE(或者 VACUUM ANALYZE) 可以保证规划器有最新的表的数据的统计。 如果没有统计数据或者统计数据太陈旧,那么规划器可能选择很差劲的查询规划,导致检索你的表的查询性能的恶化。