《Greenplum5.0 最佳实践》数据导入 (六)

Loading Data

INSERT 命令
使用 INSERT 命令将数据加载到表中。一行数据会根据分布键,从主节点分配到 segment 上。这是一种非常慢的方法,并不适合加载大量数据。

COPY 命令

Postgresql 数据库提供的 COPY 命令实质就是将 外部文件拷贝到数据库表中, 该命令一次可以插入多行数据, 效率明显高于 INSERT 命令。但是这并不是一位置数据不需要从master 节点开始执行数据导入,依旧需要master 节点完成数据分布的计算。使用数据拷贝命令,并不意味着,是并行的进程。

数据导入使用 COPY 命令,可参考如下的例子, 或者具体参看《Postgresql 手册》

COPY table FROM '/data/mydata.csv' WITH CSV HEADER;

使用 copy 命令区间在小数据集, 例如 维度表多大上万行的记录,或者一次性加载数据。
使用 COPY 命令是一种单点命令,他不需要被设置为自动提交。
可以使用多并行的 COPY 加载数据。

EXternalTables 外部表

外部表提供了一种访问外部数据源的方法。可以使用 SELECT 命令完成数据的访问和数据的抽取, 加载,转变模式 (ETL), 变化的提取方式,转变, 加载 (ETL) 模式。这些特性,是外部表成为 Greenplum 并行加载数据成为可能。

对于 ETL, 数据从数据源被抽取,使用外部转换工具在数据库之外进行转换,例如使用 Informatica 或者 Datastage ,接着将数据加载到数据库中。

使用 ETL , Greeenplum 可以通过外部表的形式去访问外部数据文件。它只能是只读文件(类型为: text, CSV, XML 文件), Web 服务器, hadoop 文件系统 (HDFS), 执行 OS 程序,或者 Greenplum 的 gpfdist 文件五福其,具体描述将在下一节。
外部表支持的 SQL 命令有 SELECT SORT JOIN 外部表的数据会被同时加载和转换。 还不偶这加载到加载表中,在数据库中转换为大的表

创建外部表的命令是 CREATE EXTERNAL TABLE, 这里还有一个 LOCATION 关键字用来定义外部数据文件的位置和 FORMAT 关键字用来定义数据文件的类型,这样便于 OS 去解析文件数据。 文件使用的文件协议是 file:// 协议, 并且文件的位置必须是超级用户可以访问到的。数据可以在分段主机之间传递,每个节点上的段数据库的文件不超过一个。

使用 Gpfdist 服务导入外部表数据

导入外部数据最快的方式是使用外部表 + GPFDIST 方式。gpfdist 是文件服务程序使用的是 HTTP 协议。使得数据是并行的导入到所有的段数据中。 一个 gpfdist 实例可以实现 200MB/sec ,多个 gpfdist 可以实现并行的数据导入。当我们是用查询语句为 INSERT INTO

SELECT FROM ;, 可以实现的是将外部表的数据插入到数据库中。这个查询语句会从 master 解析为所有段数据都执行的插入操作。但数据库连接到 gpfdist 服务器上, 并行的检查数据, 解析和校验数据,根据数据的分布键的值计算 hash 值,将该行记录发送到对应的目标段数据库中。默认情况下, 每一个 gpfdist* 实例可以接受多余来自段数据库上的64个连接。有许多段数据库和服务器参与数据加载,数据可以实现非常高效的数据加载。

使用主段数据库并行导入外部文件,设置的参数为 gp_external_max_segment。 当优化 gpfdist 的性能的时候, 这个参数用来空着段实例最大的并行数值。 将数据更多的分布在更多的 ETL 节点上。 将大的数据文件尽可能的划分为多个相等的文件,并分布到更多的文文件系统中。

运行两个 gpfdist 实例在每一个文件系统。 gpfdist 尝试使用 CPU 绑定段数据上加载数据。但是,举例子,如果有8个机架的段数据节点,有很多可用的 CPU 可以驱动更多的 gpfdist 进程。 尽可能的运行更多的 gpfdist 实例。注意绑定的 NIC, 并确保启动足够的 gpfdist 实例来处理它们。

保证所有的工作都工作这非常重要。加载的速度取决于最慢的节点。 文件加载倾斜将会引起资源瓶颈。

参数 gp_external_max_segs 用来控制 gpfdist 可以服务的段数据库的数量。 默认值是 64.我们可以通过修改 postgresql.conf 参数文件来改变这个参数的值,在 master 节点上。 改参数是影响 gpfdist 的一个因素。通常情况下, 参数 gp_external_max_segs 的值可以是 gpfdist 进程数的倍数。 例如, 这里有 12 段数据库 和 4 个 gpfdist 进程,这个计划器可能按着如下的顺讯连接


Segment 1 - gpfdist 1
Segment 2 - gpfdist 2
Segment 3 - gpfdist 3
Segment 4 - gpfdist 4
Segment 5 - gpfdist 1
Segment 6 - gpfdist 2
Segment 7 - gpfdist 3
Segment 8 - gpfdist 4
Segment 9 - gpfdist 1
Segment 10 - gpfdist 2
Segment 11 - gpfdist 3
Segment 12 - gpfdist 4
来源: https://gpdb.docs.pivotal.io/500/best_practices/data_loading.html

需要注意的事项是,在加载数据之前需要删除表中的索引, 因为随着数据的增长, 可能会引起索引节点的分裂, (B-Tree 对 I/O 不友好)。 加载完数据后在重新构建索引。

在加载完数据后,运行 ANALYZE 用来收集统计信息。通常情况下,我们是禁止自动收集统计信息的, 因为这会严重降低导入数据的速度。具体参数为 gp_autostats_mode 成为 NONE。 使用 VACUUM 回收空间。

高频率的数据加载到众多分区的列式存储表中,会引起系统性能。因为每一个时间间隔内访问的物理文件的数量很多

GPLOAD

gpload 是一个数据加载工具,是 Greenplum 并行加载外部表的接口
需要注意的是,使用 gpload 会一起 catalog 的膨胀,通过创建和删除外部表引起的。所以可以使用 gpfdist 代替他。

使用 gpload 加载数据时,需要使用特殊的 YAML 文件格式的控制文件,写起来比较恼火的。它的执行操作按照如下顺序进行。

调用 gpfdist 进程根据原始数据样式,创建临时表执行 INSERT 或者 UPDATE MERGE 操作加载数据到数据库中的目标表中删除临时表清空 gpfdist 进程

这就是一个单事务的数据导入过程

最佳实践

导入数据之前,删除数据的索引禁止数据统计信息的更新, 设置数据的参数为 gp_autostats_mode = NONE外部表不适合频繁访问和临时访问外部表没有统计信息传给查询优化器, 也就是说外部表并不会被收集统计信息,因此我们可以自己去修改 pg_class 来更新统计信息表。使用如下的语句:

UPDATE pg_class SET reltuples = 400000, relpages = 400 WHERE relname = '';,

使用 gpfdist 最大的工作带宽就是每一个ETL服务的网卡的带宽 NIC。 在 gpfdist 实例之间分发数据使用 SEGMENT REJECT LIMIT 语句用来执行 COPY 命令时, 拒绝限制每段。当任何一个段超过这个限制,命令被中止,并且没有行被添加。使用 LOG ERRORS 语句来存储错误的行。 如果某一行在格式上有错误 (例如缺失或额外的值)或不正确的数据类型。 Greenplum Database 会在内存存储错误信息和行。可以使用 gp_read_error_log() 的SQL方法去读取这个存储的信息。如果数据加载有错误,使用 VACUUM 回收空间在你讲数据加载进表后, 运行 VACUUM 在堆表上。包括系统表,使用 ANALYZE 去分析全部表。如果没有必要的话不要在 AO表上运行 VACUUM 操作。如果表是分区表, 你可以执行 VACUUMANALYZE 操作。因为分区表会因为数据加载而受到影响。 对于 异常操作 load delete update ,我们需要更新统计信息表。对于默认情况下, gpofdist 最大的记录尺寸为 32KB。 如果打入的数据的尺寸大于该值,我们需要修改参数,增加最大的导入尺寸。使用 -m 来在 gpfdist 命令上来实现。 如果使用的是 gpload 就需要我们去修改控制文件中的参数 MAX_LIMIT_LENGTH 来实现。

参看

连接地址:
https://gpdb.docs.pivotal.io/500/best_practices/data_loading.html

上一篇:json 函数介绍


下一篇:为什么不走索引, PostgreSQL