zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

POSTGRESQL COPY 命令导入数据,你还另一个更快的方案!

2023-02-18 16:23:53 时间

POSTGRESQL 数据库数据导入的核心一般都使用COPY 命令,熟悉POSTGRESQL 的同学应该对这个命令不陌生,相对于MYSQL 去一条条的执行insert命令来说,COPY 命令是POSTGRESQL 对于巨量数据导入的外挂。

以下是POSTGRESQL 一段官方的对于COPY 的解释

COPY在PostgreSQL表和标准文件系统文件之间移动数据。COPY TO将表的内容复制到文件中,而COPY FROM将数据从文件复制到表中(将数据追加到表中已经存在的内容)。COPY TO还可以复制SELECT查询的结果。

实际上copy 命令的格式主要由三个部分组成

1 标识copy命令

2 message size 标定

3 数据包(数据流)

实际上COPY 命令中的数据的传入是以数据流的方式进入到数据库中的,所以COPY 命令并不是事务,或者说不是简单的事务。建议在使用copy 命令的时候使用 copy to ,原因已经有很多同学写过这部分的东西了。

今天要说的更快的方案是一个第三方的POSTGRESQL 的工具 , pg_bulkload,命令这个命令相对于COPY 的差异在于,大,什么大,数据量大的情况下,例如将POSTGRESQL 作为数据库仓库使用的时候,导入大量的数据,或者数据导出时的一个,强有力的支持工具。

这个工具的主要特点是跨过了 shared buffers, 在跨过 shared buffers 的情况下将数据导入到数据库中。同时新的版本还具有了 ETL 的部分功能。

下面我们来安装一下这个工具,工具本身支持最新的POSTGRESQL 版本也支持老的9.X 的版本,安装直接通过rpm 包安装并未成功,建议还是通过编译的方式来进行安装,同时在编译的时候需要有对应的PG变量存在,否则安装失败。

我们先看看pg_blukload 的内部构造是怎样的,主体分为两个部分

1 read :包含了ETL 的部分和数据代码转换和过滤的功能

2 writer :跳过 shared buffer 的部分

这里的写过滤的功能是如何完成的,通过以下的部分进行功能的实现

1 记录从文件中读取并一条条的通过 filter

2 当在过滤中发生错误的时候,这条数据就不会被加载,并且将这个问题的记录写入到 parse badfile 中。

3 在过滤的过程中,会验证数据类型和字段的数量,如果不相符则判定为错误

4 对于一些组合类型的字段类型 和 set of 命令等 pg_blukload 不支持。

5 不建议导入数据中的脚本中存在函数,这样会影响导入数据的时间

6 导入数据的时候支持并行功能

7 导入的数据格式支持 CSV , 二进制,函数产生 三种方式

8 写入数据的方式主要包含了,直接加载,direct, 缓冲加载 buffer 方式,二进制方式,并行方式 parallel

下面我们产生两个测试表,同样的表结构

下面我们通过COPY 命令将CSV 数据加载到数据表中,看看时间有多长 100万行数据,整体时间在 1.5秒左右,速度还是很快的。

下面我们转换模式,将数据通过pg_blukload的方式来进行数据的加载,时间1.13秒

使用了pg_blukload 相对COPY的模式,只使用原有时间的76%, 可以想到如果数据量在大一些,则节省的时间是可观的。但需要注意的是,CSV 文件不要有页头,也就是字段的名字一列,否则会当成错误的,导致数据无法被载入。

除了在性能上的优势,pg_blukload 在以下几个方面也是比COPY 要完善的多

1 他具有日志功能,他具有 操作日志, 错误日志,以及重复数据日志等

2 可以通过日志来做成导入 控制文件简化操作,固话操作

3 可以加入一些options 将操作灵活化

下面的命令意思为,导入CSV文件,并且间隔符号是 竖线,同时将原表的数据先清空后,在不跳过buffer 的情况下导入数据。

pg_bulkload

-i /home/postgres/bulk.txt

-O tb_asher

-l /home/postgres/t_output.log

-P /home/postgres/t__bad.txt

-o "TYPE=CSV"

-o "DELIMITER=|"

-o "TRUNCATE=YES"

-o "WRITER=BUFFERED"

另外pg_blukload 最大的重点是,跳过buffer ,也就是不在有wal日志,如何证明这点,我们看看下面的证明过程

我们还是讲上面的操作重复,在每个操作后,我们查看wal current的状态。

下面的操作中有一个问题,不知道大家看没看出来,但已经证明了我的copy操作产生了 wal 日志。

我们在尝试通过pg_blukload 加载数据,通过下图可以看到,并未走日志,也证实了通过pg_blukload 默认数据是不会加载到 shared_buffer 中的事实

所以在基于数据仓库,或大量数据导入的情况下通过pg_blukload 是一个好的加速数据导入的方法。