热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PostgreSQL中批量导入数据的优化方法

本文介绍了在PostgreSQL中批量导入数据时的优化方法。包括使用unlogged表、删除重建索引、删除重建外键、禁用触发器、使用COPY方法、批量插入等。同时还提到了一些参数优化的注意事项,如设置effective_cache_size、shared_buffer等,并强调了在导入大量数据后使用analyze命令重新收集统计信息的重要性。

我们常常需要向数据库中导入数据,如果一次性导入大量的数据必然会对性能产生影响,而且这个时间可能还会特别长。这个可能受多方面的影响,例如:表上存在索引、触发器、磁盘IO等等因素。

那么在PostgreSQL中有什么好的方法来处理批量导入数据这类问题呢,又或者说批量导入数据时我们有哪些优化方法呢?

方法1:修改表为unlogged

pg9.5之后开始支持unlogged表,这个和Oracle中设置表属性为nologging是一样的:让指定的表上进行操作时不产生wal日志。

ALTER TABLE SET UNLOGGED

ALTER TABLE LOGGED

但是由于操作不会产生日志,那么需要注意一旦数据库出现异常导致重启,那么unlogged表中数据将会被清空。
这里说明下:如果数据库是正常关闭的,unlogged表数据是不会丢失的。

除此之外,unlogged表也不会传输到备库,那么就需要在数据导入前停止主备复制,导入完成后再重新同步。

因此在使用unlogged表之前,我们建议:

  • 修改表为unlogged前先进行数据备份;
  • 数据导入后,立刻重新进行数据同步;

方法2:删除并重建索引

索引在批量数据插入过程中可能会造成严重延迟。 这是因为在添加每一行时,相应的索引条目也必须更新。

因此我们建议在开始批量插入之前尽可能地删除目标表中的索引,并在导入完成后重新创建索引。 同样,在大型表上创建索引可能很耗时,但通常比在导入数据期间更新索引要快。

DROP INDEX ,

CREATE INDEX ON (column1, …,column n)

在创建索引之前临时增加maintenance_work_mem配置参数。增加的工作内存可以帮助更快地创建索引。

方法3:删除并重建外键

与索引一样,外键约束也会影响批量负载性能。 这是因为每个插入行中的每个外键都必须检查是否存在相应的主键。 PostgreSQL中内部是使用触发器来执行检查。 所以当加载大量行时,必须为每一行触发此触发器,从而增加开销。

因此一般我们建议将目标表中所有外键删除,在单个事务中加载数据,然后在提交事务后重新创建外键。

ALTER TABLE
DROP CONSTRAINT
BEGIN TRANSACTION

COMMIT
ALTER TABLE
ADD CONSTRAINT
FOREIGN KEY ()
REFERENCES ()...

同样的,增加maintenance_work_mem配置参数可以提高重新创建外键约束的性能。

方法4:禁用触发器

插入或删除触发器(如果加载过程也涉及从目标表中删除记录)可能会导致批量数据加载的延迟。 这是因为每个触发器都有需要检查的逻辑和在插入或删除每一行之后需要完成的操作。

我们建议在批量加载数据之前禁用目标表中的所有触发器,并在加载完成后启用它们。禁用所有触发器还包括强制执行外键约束检查的系统触发器。

ALTER TABLE DISABLE TRIGGER ALL

ALTER TABLE ENABLE TRIGGER ALL

方法5:使用COPY方法

使用COPY命令从一个或多个文件加载数据。COPY针对批量数据加载进行了优化。它比运行大量的插入语句,甚至是多值插入,更有效。pg12开始支持在copy命令中增加where过滤,使用起来也更加灵活。

COPY [( column1>, … , )]
FROM ''
WITH (, , … , )

方法6:使用批量插入

执行多个insert语句进行插入的性能远远不如批量插入。这是因为每个单独的insert命令都必须由查询优化器解析和准备,通过所有约束检查,作为一个单独的事务运行,并产生WAL日志。 使用批量INSERT语句可以节省此开销。

INSERT INTO (, , …, )
VALUES
(, , …, ),
(, , …, ),
(, , …, ),
(, , …, ),
...

与之类似的是,我们可以关闭pg中的自动提交,来手动进行批量的提交。而不是每执行一条语句就进行一次提交,而是将多条语句放在一个事务中。

这里我们可以设置commit_delay来实现,指定提交状态的事务达到commit_siblings时进行一次性提交,这样只需要flush一次wal日志,从而减少wal io。

方法7:其它注意事项

除此之外,我们可以对一些参数进行优化,例如:设置effective_cache_size 为内存的50%,设置shared_buffer为内存的25%,还可以适当增加max_wal_size。

还有最后一点需要注意的是:
批量导入大量数据后记得使用analyze命令来重新收集统计信息。


推荐阅读
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了在Oracle数据库中创建序列时如何选择cache或nocache参数。cache参数可以提高序列的存取速度,但可能会导致序列丢失;nocache参数可以避免序列丢失,但在高并发访问时可能导致性能问题。文章详细解释了两者的区别和使用场景。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
author-avatar
未来不是梦2602932127
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有