华为云用户手册

  • 写入和读写操作 关于写入和读写操作的命令: INSERT,可向表中插入一行或多行数据。 UPDATE,可修改表中现有数据。 DELETE,可删除表中现有数据。 COPY,导入数据。 INSERT和COPY是纯写入的操作。并发写入操作,需要等待,对同一个表的操作,当事务T1的INSERT或COPY未解除锁定时,事务T2的INSERT或COPY需等待,事务T1解除锁定时,事务T2正常继续。 UPDATE和DELETE是读写操作(先查询出要操作的行)。UPDATE和DELETE执行前需要先查询数据,由于并发事务彼此不可见,所以UPDATE和DELETE操作是读取事务发生前提交的数据的快照。写入操作,是行级锁,当事务T1和事务T2并发更新同一行时,后发生的事务T2会等待,根据设置的等待时长,若超时事务T1未提交则事务T2执行失败;当事务T1和事务T2并发更新的行不同时,事务T1和事务T2都会执行成功。 父主题: 管理并发写入操作
  • 事务隔离说明 GaussDB 基于MVCC(多版本并发控制)并结合两阶段锁的方式进行事务管理,其特点是读写之间不阻塞。SELECT是纯读操作,UPDATE和DELETE是读写操作。 读写操作和纯读操作之间并不会发生冲突,读写操作之间也不会发生冲突。每个并发事务在事务开始时创建事务快照,并发事务之间不能检测到对方的更改。 读已提交隔离级别中,如果事务T1提交后,事务T2就可以看到事务T1更改的结果。 可重复读级别中,如果事务T1提交事务前事务T2开始执行,则事务T1提交后,事务T2依旧看不到事务T1更改的结果,保证了一个事务开始后,查询的结果前后一致,不受其他事务的影响。 读写操作,支持的是行级锁,不同的事务可以并发更新同一个表,只有更新同一行时才需等待,后发生的事务会等待先发生的事务提交后,再执行更新操作。 READ COMMITTED:读已提交隔离级别,事务只能读到已提交的数据而不会读到未提交的数据,这是缺省值。 REPEATABLE READ: 事务只能读到事务开始之前已提交的数据,不能读到未提交的数据以及事务执行期间其它并发事务提交的修改。 父主题: 管理并发写入操作
  • 对表执行VACUUM 如果导入过程中,进行了大量的更新或删除行时,应运行VACUUM FULL命令,然后运行ANALYZE命令。大量的更新和删除操作,会产生大量的磁盘页面碎片,从而逐渐降低查询的效率。VACUUM FULL可以将磁盘页面碎片恢复并交还操作系统。 对表执行VACUUM FULL。 以表product_info为例,VACUUM FULL命令如下: 1 openGauss=# VACUUM FULL product_info VACUUM 父主题: 导入数据
  • 表自动分析 GaussDB提供了GUC参数autovacuum用于控制数据库自动清理功能的启动。 autovacuum设置为on时,系统定时启动autovacuum线程来进行表自动分析,如果表中数据量发生较大变化达到阈值时,会触发表自动分析,即autoanalyze。 对于空表而言,当表中插入数据的行数大于50时,会触发表自动进行ANALYZE。 对于表中已有数据的情况,阈值设定为50+10%*reltuples,其中reltuples是表的总行数。 autovacuum自动清理功能的生效还依赖于下面两个GUC参数: track_counts 参数需要设置为on,表示开启收集收据库统计数据功能。 autovacuum_max_workers参数需要大于0,该参数表示能同时运行的自动清理线程的最大数量。 autoanalyze只支持默认采样方式,不支持百分比采样方式。 多列统计信息(当前特性是实验室特性,使用时请联系华为工程师提供技术支持)仅支持百分比采样,因此autoanalyze不收集多列统计信息。 autoanalyze支持行存表和列存表,不支持外表、OBS外表(当前特性是实验室特性,使用时请联系华为工程师提供技术支持)、临时表、unlogged表和toast表。
  • 示例 对目标表staffs选择合适的分布列。 分析表staffs的数据源特征,选择数据重复度低且分布均匀的备选分布列staff_ID、FIRST_NAME和LAST_NAME。 先选择staff_ID作为分布列,创建目标表staffs。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 openGauss=# CREATE TABLE staffs ( staff_ID NUMBER(6) not null, FIRST_NAME VARCHAR2(20), LAST_NAME VARCHAR2(25), EMAIL VARCHAR2(25), PHONE_NUMBER VARCHAR2(20), HIRE_DATE DATE, employment_ID VARCHAR2(10), SALARY NUMBER(8,2), COMMISSION_PCT NUMBER(2,2), MANAGER_ID NUMBER(6), section_ID NUMBER(4) ) DISTRIBUTE BY hash(staff_ID); 向目标表staffs中导入部分数据。 根据以下查询所得,集群环境中主DN数为8个,则建议导入的记录数为80000条。 1 2 3 4 5 openGauss=# SELECT count(*) FROM pgxc_node where node_type='D'; count ------- 8 (1 row) 校验以staff_ID为分布列的目标表staffs的数据倾斜性。 1 2 3 4 5 6 7 8 9 10 11 12 openGauss=# SELECT a.count,b.node_name FROM (select count(*) as count,xc_node_id FROM staffs GROUP BY xc_node_id) a, pgxc_node b WHERE a.xc_node_id=b.node_id ORDER BY a.count desc; count | node_name ------+----------- 11010 | datanode4 10000 | datanode3 12001 | datanode2 8995 | datanode1 10000 | datanode5 7999 | datanode6 9995 | datanode7 10000 | datanode8 (8 rows) 根据上一步骤查询所得,各DN上数据分布差大于10%,数据分布倾斜。所以从步骤1的备选分布列中删除该列,并删除目标表staffs。 1 openGauss=# DROP TABLE staffs; 尝试选择staff_ID、FIRST_NAME和LAST_NAME的组合作为分布列,创建目标表staffs。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 openGauss=# CREATE TABLE staffs ( staff_ID NUMBER(6) not null, FIRST_NAME VARCHAR2(20), LAST_NAME VARCHAR2(25), EMAIL VARCHAR2(25), PHONE_NUMBER VARCHAR2(20), HIRE_DATE DATE, employment_ID VARCHAR2(10), SALARY NUMBER(8,2), COMMISSION_PCT NUMBER(2,2), MANAGER_ID NUMBER(6), section_ID NUMBER(4) ) DISTRIBUTE BY hash(staff_ID,FIRST_NAME,LAST_NAME); 校验以staff_ID、FIRST_NAME和LAST_NAME的组合为分布列的目标表staffs的数据倾斜性。 1 2 3 4 5 6 7 8 9 10 11 12 openGauss=# SELECT a.count,b.node_name FROM (select count(*) as count,xc_node_id FROM staffs GROUP BY xc_node_id) a, pgxc_node b WHERE a.xc_node_id=b.node_id ORDER BY a.count desc; count | node_name ------+----------- 10010 | datanode4 10000 | datanode3 10001 | datanode2 9995 | datanode1 10000 | datanode5 9999 | datanode6 9995 | datanode7 10000 | datanode8 (8 rows) 根据上一步骤查询所得,各DN上数据分布差小于10%,数据分布均衡,选择的分布列合适。 清理已导入小批量数据。 1 openGauss=# TRUNCATE TABLE staffs; 导入全量数据,以完成数据迁移。
  • 操作步骤 分析数据源特征,选择若干个键值重复度小,数据分布比较均匀的备选分布列。 从步骤1中选择一个备选分布列创建目标表。 1 2 3 4 5 6 7 8 9 10 11 12 13 CREATE [ [ GLOBAL | LOCAL ] [ TEMPORARY | TEMP ] | UN LOG GED ] TABLE [ IF NOT EXISTS ] table_name ({ column_name data_type [ compress_mode ] [ COLLATE collation ] [ column_constraint [ ... ] ] | table_constraint | LIKE source_table [ like_option [...] ] } [, ... ]) [ WITH ( {storage_parameter = value} [, ... ] ) ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS } ] [ COMPRESS | NOCOMPRESS ] [ TABLESPACE tablespace_name ] [ DISTRIBUTE BY { REPLICATION | { HASH ( column_name [,...] ) | { RANGE ( column_name [, ...] ) SLICE REFEREN CES tablename | ( slice_less_than_item [, ...] | slice_start_end_item [, ...] ) | { LIST ( column_name [, ...] ) SLICE REFERENCES tablename | ( slice_values_item [, ...] ) }}} } ] 参照前面章节中的办法向目标表中导入小批量数据。 对于单个数据源文件,在导入时,可通过均匀切割,导入部分切割后的数据源文件来验证数据倾斜性。 检验数据倾斜性。命令中的table_name ,请填入实际的目标表名。 1 openGauss=# SELECT a.count,b.node_name FROM (SELECT count(*) AS count,xc_node_id FROM table_name GROUP BY xc_node_id) a, pgxc_node b WHERE a.xc_node_id=b.node_id ORDER BY a.count desc; 若各DN上数据分布差小于10%,表明数据分布均衡,选择的分布列合适。请清理已导入小批量数据,导入全量数据,以完成数据迁移。 若各DN上数据分布差大于等于10%,表明数据分布倾斜,请从步骤1的备选分布列中删除该列,删除目标表,并重复步骤2 、步骤3 、步骤4 和步骤5。 (可选)如果上述步骤不能选出适合的分布列,需要从备选分布列选择多个列的组合作为分布列来完成数据迁移。
  • 背景信息 GaussDB是采用Shared-Nothing架构的MPP(Massive Parallel Processor,大规模并发处理)系统,采用水平分布的方式,将业务数据表的元组按合适的分布策略分散存储在所有的DN。 当前产品支持复制(Replication)、散列(Hash)、范围(Range)和列表(List)等多种用户表分布策略。 Replication方式:在每一个DN上存储一份全量表数据。对于数据量比较小的表建议采取Replication分布策略。 Hash方式:采用这种分布方式,需要为用户表指定一个分布列(distribute key)。当插入一条记录时,系统会根据分布列的值进行hash运算后,将数据存储在对应的DN中。对于数据量比较大的表建议采取Hash分布策略。 Range方式和List方式:用于用户指定数据分布规则的场景,根据指定字段取值与预先设定的范围或具体值来确定该元组的目标节点。
  • 操作步骤 使用CREATE TABLE AS语句创建表customer_t的临时表副本customer_t_temp。 1 openGauss=# CREATE TEMP TABLE customer_t_temp AS SELECT * FROM customer_t; 与使用永久表相比,使用临时表可以提高性能,但存在丢失数据的风险。临时表只在当前会话可见,本会话结束后将自动删除。如果数据丢失是不可接受的,请使用永久表。 临时表与普通表的存放位置无差,也可指定tablespace存放。本地临时表应用过多可能会导致系统表膨胀,但总体影响在可接受范围内。 截断当前表customer_t。 1 openGauss=# TRUNCATE customer_t; 使用INSERT INTO…SELECT语句从副本中向原始表中填充数据。 1 openGauss=# INSERT INTO customer_t (SELECT * FROM customer_t_temp); 删除临时表副本customer_t_temp。 1 openGauss=# DROP TABLE customer_t_temp;
  • 操作步骤 使用CREATE TABLE LIKE语句创建表customer_t的副本customer_t_copy。 1 openGauss=# CREATE TABLE customer_t_copy (LIKE customer_t); 使用INSERT INTO…SELECT语句向副本填充原始表中的数据。 1 openGauss=# INSERT INTO customer_t_copy (SELECT * FROM customer_t); 删除原始表。 1 openGauss=# DROP TABLE customer_t; 使用ALTER TABLE语句将副本重命名为原始表名称。 1 openGauss=# ALTER TABLE customer_t_copy RENAME TO customer_t;
  • 操作步骤 执行如下步骤对表customer_t进行深层复制。 使用CREATE TABLE语句创建表customer_t的副本customer_t_copy。 1 2 3 4 5 6 openGauss=# CREATE TABLE customer_t_copy ( c_customer_sk integer, c_customer_id char(5), c_first_name char(6), c_last_name char(8) ) ; 使用INSERT INTO…SELECT语句向副本填充原始表中的数据。 1 openGauss=# INSERT INTO customer_t_copy (SELECT * FROM customer_t); 删除原始表。 1 openGauss=# DROP TABLE customer_t; 使用ALTER TABLE语句将副本重命名为原始表名称。 1 openGauss=# ALTER TABLE customer_t_copy RENAME TO customer_t;
  • 深层复制 数据导入后,如果需要修改表的分布键、分区键、或者将行存表改列存、添加PCK(Partial Cluster Key)约束等场景下,可以使用深层复制的方式对表进行调整。深层复制是指重新创建表,然后使用批量插入填充表的过程。 GaussDB提供了三种深层复制的方式供用户选择。 使用CREATE TABLE执行深层复制 使用CREATE TABLE LIKE执行深层复制 通过创建临时表并截断原始表来执行深层复制 父主题: 导入数据
  • 操作步骤 创建源表products,并插入数据。 1 2 3 4 5 6 7 8 9 10 11 openGauss=# CREATE TABLE products ( product_id INTEGER, product_name VARCHAR2(60), category VARCHAR2(60) ); openGauss=# INSERT INTO products VALUES (1502, 'olympus camera', 'electrncs'), (1601, 'lamaze', 'toys'), (1666, 'harry potter', 'toys'), (1700, 'wait interface', 'books'); 创建目标表newproducts,并插入数据。 1 2 3 4 5 6 7 8 9 10 11 12 openGauss=# CREATE TABLE newproducts ( product_id INTEGER, product_name VARCHAR2(60), category VARCHAR2(60) ); openGauss=# INSERT INTO newproducts VALUES (1501, 'vivitar 35mm', 'electrncs'), (1502, 'olympus ', 'electrncs'), (1600, 'play gym', 'toys'), (1601, 'lamaze', 'toys'), (1666, 'harry potter', 'dvd'); 使用MERGE INTO 语句将源表products的数据合并至目标表newproducts。 1 2 3 4 5 6 7 openGauss=# MERGE INTO newproducts np USING products p ON (np.product_id = p.product_id ) WHEN MATCHED THEN UPDATE SET np.product_name = p.product_name, np.category = p.category WHEN NOT MATCHED THEN INSERT VALUES (p.product_id, p.product_name, p.category) ; 上述语句中使用的参数说明,请见表1。更多信息,请参见MERGE INTO。 表1 MERGE INTO语句参数说明 参数 说明 举例 INTO 子句 指定需要更新或插入数据的目标表。 目标表支持指定别名。 目标表支持复制表,但复制表不能带有含volatile函数的列(如自增列);如果enable_stream_operator=off,目标复制表需要带有主键或某一列满足unique not null约束。 取值:newproducts np 说明:名为newproducts,别名为np的目标表。 USING子句 指定源表。源表支持指定别名。 目标表是复制表时,源表也需要是复制表。 取值:products p 名为products,别名为p的源表。 ON子句 指定目标表和源表的关联条件。 关联条件中的字段不支持更新。 取值:np.product_id = p.product_id 说明:指定的关联条件为,目标表newproducts的product_id字段和源表products的product_id字段相等。 WHEN MATCHED子句 当源表和目标表中数据针对关联条件可以匹配上时,选择WHEN MATCHED子句进行UPDATE操作。 仅支持指定一个WHEN MATCHED子句。 WHEN MATCHED子句可缺省,缺省时,对于满足ON子句条件的行,不进行任何操作。 若目标表中存在分布列,则该列不支持更新。 取值:WHEN MATCHED THEN UPDATE SET np.product_name = p.product_name, np.category = p.category 说明:当满足ON子句条件时,将目标表newproducts的product_name、category字段的值替换为源表products相对应字段的值。 WHEN NOT MATCHED子句 当源表和目标表中数据针对关联条件无法匹配时,选择WHEN NOT MATCHED子句进行INSERT操作。 仅支持指定一个WHEN NOT MATCHED子句。 WHEN NOT MATCHED子句可缺省。 不支持INSERT子句中包含多个VALUES。 WHEN MATCHED和WHEN NOT MATCHED子句顺序可以交换,可以缺省其中一个,但不能同时缺省。 取值:WHEN NOT MATCHED THEN INSERT VALUES (p.product_id, p.product_name, p.category) 说明:将源表products中,不满足ON子句条件的行插入目标表products。 查询合并后的目标表newproducts。 1 openGauss=# SELECT * FROM newproducts; 返回信息如下: product_id | product_name | category ------------+----------------+----------- 1501 | vivitar 35mm | electrncs 1502 | olympus camera | electrncs 1666 | harry potter | toys 1600 | play gym | toys 1601 | lamaze | toys 1700 | wait interface | books (6 rows)
  • 操作步骤 假设存在表customer_t,表结构如下: 1 2 3 4 5 6 openGauss=# CREATE TABLE customer_t ( c_customer_sk integer, c_customer_id char(5), c_first_name char(6), c_last_name char(8) ) ; 可以使用如下DML命令对表进行数据更新。 使用INSERT向表中插入数据。 向表customer_t中插入一行。 1 openGauss=# INSERT INTO customer_t (c_customer_sk, c_customer_id, c_first_name,c_last_name) VALUES (3769, 5, 'Grace','White'); 向表customer_t中插入多行数据。 1 2 3 4 5 openGauss=# INSERT INTO customer_t (c_customer_sk, c_customer_id, c_first_name,c_last_name) VALUES (6885, 1, 'Joes', 'Hunter'), (4321, 2, 'Lily','Carter'), (9527, 3, 'James', 'Cook'), (9500, 4, 'Lucy', 'Baker'); 更多关于INSERT的使用方法,请参见向表中插入数据。 使用UPDATE更新表中数据。修改字段c_customer_id值为0。 1 openGauss=# UPDATE customer_t SET c_customer_id = 0; 更多关于UPDATE的使用方法,请参见UPDATE。 使用DELETE删除表中的行。 可以使用WHERE子句指定需要删除的行,若不指定即删除表中所有的行,只保留数据结构。 1 openGauss=# DELETE FROM customer_t WHERE c_last_name = 'Baker'; 更多关于DELETE的使用方法,请参见DELETE。 使用TRUNCATE命令快速从表中删除所有的行。 1 openGauss=# TRUNCATE TABLE customer_t; 更多关于TRUNCATE的使用方法,请参见TRUNCATE。 删除表时,DELETE语句每次删除一行数据而TRUNCATE语句是通过释放表存储的数据页来删除数据,使用TRUNCATE语句比使用DELETE语句更加快速。 使用DELETE语句删除表时,仅删除数据,不释放存储空间。使用TRUNCATE语句删除表时,删除数据且释放存储空间。
  • \copy命令 \copy命令格式以及说明参见表1。 表1 \copy元命令说明 语法 说明 \copy { table [ ( column_list ) ] | ( query ) } { from | to } { filename | stdin | stdout | pstdin | pstdout } [ with ] [ binary ] [ oids ] [ delimiter [ as ] 'character' ] [ useeof ] [ null [ as ] 'string' ] [ csv [ header ] [ quote [ as ] 'character' ] [ escape [ as ] 'character' ] [ force quote column_list | * ] [ force not null column_list ] ] 在任何gsql客户端登录数据库成功后,可以使用该命令进行数据的导入/导出。但是与SQL的COPY命令不同,该命令读取/写入的文件是本地文件,而非数据库服务器端文件;所以,要操作的文件的可访问性、权限等,都是受限于本地用户的权限。 说明: \COPY只适合小批量、格式良好的数据导入,不会对非法字符做预处理,也无容错能力,无法适用于含有异常数据的场景。导入数据应优先选择GDS或COPY。
  • 示例2:从MySQL进行数据迁移 下面示例演示如何通过CopyManager从MySQL进行数据迁移的过程。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 import java.io.StringReader; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.postgresql.copy.CopyManager; import org.postgresql.core.BaseConnection; public class Migration{ public static void main(String[] args) { String url = new String("jdbc:postgresql://localhost:8000/postgres"); //数据库URL String user = new String("username"); //GaussDB用户名 String pass = new String("passwd"); //GaussDB密码 String tablename = new String("migration_table_1"); //定义表信息 String delimiter = new String("|"); //定义分隔符 String encoding = new String("UTF8"); //定义字符集 String driver = "org.postgresql.Driver"; StringBuffer buffer = new StringBuffer(); //定义存放格式化数据的缓存 try { //获取源数据库查询结果集 ResultSet rs = getDataSet(); //遍历结果集,逐行获取记录 //将每条记录中各字段值,按指定分隔符分割,由换行符结束,拼成一个字符串 //把拼成的字符串,添加到缓存buffer while (rs.next()) { buffer.append(rs.getString(1) + delimiter + rs.getString(2) + delimiter + rs.getString(3) + delimiter + rs.getString(4) + "\n"); } rs.close(); try { //建立目标数据库连接 Class.forName(driver); Connection conn = DriverManager.getConnection(url, user, pass); BaseConnection baseConn = (BaseConnection) conn; baseConn.setAutoCommit(false); //初始化表信息 String sql = "Copy " + tablename + " from STDIN with (DELIMITER " + "'" + delimiter + "'" +","+ " ENCODING " + "'" + encoding + "')"; //提交缓存buffer中的数据 CopyManager cp = new CopyManager(baseConn); StringReader reader = new StringReader(buffer.toString()); cp.copyIn(sql, reader); baseConn.commit(); reader.close(); baseConn.close(); } catch (ClassNotFoundException e) { e.printStackTrace(System.out); } catch (SQLException e) { e.printStackTrace(System.out); } } catch (Exception e) { e.printStackTrace(); } } //******************************** // 从源数据库返回查询结果集 //********************************* private static ResultSet getDataSet() { ResultSet rs = null; try { Class.forName("com.mysql.jdbc.Driver").newInstance(); Connection conn = DriverManager.getConnection("jdbc:mysql://10.119.179.227:3306/jack?useSSL=false&allowPublicKeyRetrieval=true", "jack", "xxxxxxxxx"); Statement stmt = conn.createStatement(); rs = stmt.executeQuery("select * from migration_table"); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return rs; } } 父主题: 使用COPY FROM STDIN导入数据
  • 示例1:通过本地文件导入导出数据 在使用JAVA语言基于GaussDB进行二次开发时,可以使用CopyManager接口,通过流方式,将数据库中的数据导出到本地文件或者将本地文件导入数据库中,文件格式支持 CS V、TEXT等格式。 样例程序如下,执行时需要加载GaussDB的JDBC驱动。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 import java.sql.Connection; import java.sql.DriverManager; import java.io.IOException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.sql.SQLException; import org.postgresql.copy.CopyManager; import org.postgresql.core.BaseConnection; public class Copy{ public static void main(String[] args) { String urls = new String("jdbc:postgresql://localhost:8000/postgres"); //数据库URL String username = new String("username"); //用户名 String password = new String("passwd"); //密码 String tablename = new String("migration_table"); //定义表信息 String tablename1 = new String("migration_table_1"); //定义表信息 String driver = "org.postgresql.Driver"; Connection conn = null; try { Class.forName(driver); conn = DriverManager.getConnection(urls, username, password); } catch (ClassNotFoundException e) { e.printStackTrace(System.out); } catch (SQLException e) { e.printStackTrace(System.out); } // 将表migration_table中数据导出到本地文件d:/data.txt try { copyToFile(conn, "d:/data.txt", "(SELECT * FROM migration_table)"); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } //将d:/data.txt中的数据导入到migration_table_1中。 try { copyFromFile(conn, "d:/data.txt", tablename1); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 将表migration_table_1中的数据导出到本地文件d:/data1.txt try { copyToFile(conn, "d:/data1.txt", tablename1); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void copyFromFile(Connection connection, String filePath, String tableName) throws SQLException, IOException { FileInputStream fileInputStream = null; try { CopyManager copyManager = new CopyManager((BaseConnection)connection); fileInputStream = new FileInputStream(filePath); copyManager.copyIn("COPY " + tableName + " FROM STDIN ", fileInputStream); } finally { if (fileInputStream != null) { try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } public static void copyToFile(Connection connection, String filePath, String tableOrQuery) throws SQLException, IOException { FileOutputStream fileOutputStream = null; try { CopyManager copyManager = new CopyManager((BaseConnection)connection); fileOutputStream = new FileOutputStream(filePath); copyManager.copyOut("COPY " + tableOrQuery + " TO STDOUT", fileOutputStream); } finally { if (fileOutputStream != null) { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } } 父主题: 使用COPY FROM STDIN导入数据
  • 常用方法 表1 CopyManager常用方法 返回值 方法 描述 throws CopyIn copyIn(String sql) - SQLException long copyIn(String sql, InputStream from) 使用COPY FROM STDIN从InputStream中快速向数据库中的表导入数据。 SQLException,IOException long copyIn(String sql, InputStream from, int bufferSize) 使用COPY FROM STDIN从InputStream中快速向数据库中的表导入数据。 SQLException,IOException long copyIn(String sql, Reader from) 使用COPY FROM STDIN从Reader中快速向数据库中的表导入数据。 SQLException,IOException long copyIn(String sql, Reader from, int bufferSize) 使用COPY FROM STDIN从Reader中快速向数据库中的表导入数据。 SQLException,IOException CopyOut copyOut(String sql) - SQLException long copyOut(String sql, OutputStream to) 将一个COPY TO STDOUT的结果集从数据库发送到OutputStream类中。 SQLException,IOException long copyOut(String sql, Writer to) 将一个COPY TO STDOUT的结果集从数据库发送到Writer类中。 SQLException,IOException
  • 关于COPY FROM STDIN导入数据 这种方式适合数据写入量不太大, 并发度不太高的场景。 用户可以使用以下方式通过COPY FROM STDIN语句直接向GaussDB写入数据。 通过键盘输入向GaussDB写入数据。详细请参见COPY。 通过JDBC驱动的CopyManager接口从文件或者数据库向GaussDB写入数据。此方法支持COPY语法中copy option的所有参数。 父主题: 使用COPY FROM STDIN导入数据
  • 通过INSERT语句直接写入数据 用户可以通过以下方式执行INSERT语句直接向GaussDB写入数据: 使用GaussDB提供的客户端工具向GaussDB写入数据。 请参见向表中插入数据。 通过JDBC/ODBC驱动连接数据库执行INSERT语句向GaussDB写入数据。 详细内容请参见连接数据库。 GaussDB支持完整的数据库事务级别的增删改操作。INSERT是最简单的一种数据写入方式,这种方式适合数据写入量不大, 并发度不高的场景。 父主题: 导入数据
  • 示例3:Private策略导入 假设集群共有4台主机,8个主DN,即每个主机上有2个主DN。待导入数据文件有8个,每个50MB。文件格式为CSV。 以操作系统用户omm登录CN所在主机。 使用如下命令连接数据库。 gsql -d postgres -p 8000 postgres为需要连接的数据库名称,8000为CN的端口号。 连接成功后,系统显示类似如下信息: gsql((GaussDB Kernel VxxxRxxxCxx build f521c606) compiled at 2021-09-16 14:55:22 commit 2935 last mr 6385 release) Non-SSL connection (SSL connection is recommended when requiring high-security) Type "help" for help. openGauss=# 查询各主机上的DN名称。 1 openGauss=# SELECT node_name,node_host FROM pgxc_node WHERE node_type='D'; 示例: 1 2 3 4 5 6 7 8 9 10 11 12 openGauss=# SELECT node_name,node_host FROM pgxc_node WHERE node_type='D'; node_name | node_host --------------+---------------- dn_6001_6002 | 192.168.0.11 dn_6003_6004 | 192.168.0.11 dn_6005_6006 | 192.168.0.12 dn_6007_6008 | 192.168.0.12 dn_6009_6010 | 192.168.0.13 dn_6011_6012 | 192.168.0.13 dn_6013_6014 | 192.168.0.14 dn_6015_6016 | 192.168.0.14 (8 rows) 将数据源文件上传每个DN所在的主机。 以普通用户登录集群的每台主机,创建数据文件存放目录“/input_data”,以及以该主机上“DN名称”命名的子目录。 以3.查询各主机上的DN名称。所查到的IP为“192.168.0.11”的节点为例,创建数据存放目录。根据上一步骤查询所得,该节点上存在2个DN,名称分别为“dn_6001_6002”和“dn_6003_6004”。 mkdir -p /input_data mkdir -p /input_data/dn_6001_6002 mkdir -p /input_data/dn_6003_6004 将数据源文件均匀分发到集群各主机上一步骤中所创建的子目录中。 修改各主机上待导入数据源文件及数据文件目录“/input_data”的属主为omm。 chown -R omm:dbgrp /input_data 创建导入的目标表reasons。 1 2 3 4 5 6 openGauss=# CREATE TABLE reasons ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ); 创建外表foreign_tpcds_reasons用于接收数据。 其中设置的导入模式信息如下所示: 导入模式为Private模式。 由于数据源文件存放在集群节点上以DN名命令的文件夹下,可以以本地文件方式访问,所以设置参数“location”为“file:///input_data/*”。 设置的数据格式信息是根据导出时设置的详细数据格式参数信息指定的,参数设置如下所示: 数据源文件格式(format)为CSV。 字段分隔符(delimiter)为逗号。 引号字符(quote)为0x1b。 数据文件中空值(null)为没有引号的空字符串。 设置的导入容错性如下所示: 允许出现的数据格式错误个数(PER NODE REJECT LIMIT 'value')为unlimited,即接受导入过程中所有数据格式错误。 将数据导入过程中出现的数据格式错误信息(LOG INTO error_table_name)写入表err_tpcds_reasons。 1 2 3 4 5 6 7 openGauss=# CREATE FOREIGN TABLE foreign_tpcds_reasons ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) SERVER gsmpp_server OPTIONS (location 'file:///input_data/*', format 'CSV', mode 'private', delimiter ',', quote E'\x1b', null '')LOG INTO err_tpcds_reasonS PER NODE REJECT LIMIT 'unlimited'; 将数据导入reasons。 1 openGauss=# INSERT INTO reasons SELECT * FROM foreign_tpcds_reasons; 查询错误信息表err_tpcds_reasons,处理数据加载错误。详细请参见处理错误表。 1 openGauss=# SELECT * FROM err_tpcds_reasons; 父主题: 示例
  • 示例2:Shared策略导入 导入前的准备。 假设TEXT格式的数据源文件“foreign_tpcds_reasons.dat.0”保存在192.168.0.90服务器上“/input_data”目录下。 在数据服务器上配置NFS服务。具体配置方法可以参考SUSE DOC:管理指南-配置NFS服务器。 NFS服务及其数据传输的安全性由用户自己保证,建议用户在可信域内使用NFS服务。 在数据服务器上启动NFS服务。 service nfs start 以普通用户在GaussDB各DN所在的主机创建数据文件目录上“/input_data”,并将数据源服务器mount到此目录下。 cd /input_data mount -t nfs 192.168.0.90:/input_data /input_data 以操作系统用户omm登录CN所在主机。 使用如下命令连接数据库。 gsql -d postgres -p 8000 postgres为需要连接的数据库名称,8000为CN的端口号。 连接成功后,系统显示类似如下信息: gsql((GaussDB Kernel VxxxRxxxCxx build f521c606) compiled at 2021-09-16 14:55:22 commit 2935 last mr 6385 release) Non-SSL connection (SSL connection is recommended when requiring high-security) Type "help" for help. openGauss=# 创建导入目标表reasons。 1 2 3 4 5 6 openGauss=# CREATE TABLE reasons ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ); 创建外表foreign_tpcds_reasons用于接收数据服务器上的数据。 1 2 3 4 5 6 openGauss=# CREATE FOREIGN TABLE foreign_tpcds_reasons ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) SERVER gsmpp_server OPTIONS (location 'file:///input_data/foreign_tpcds_reasons.dat.0', format 'TEXT', mode 'shared', delimiter E'\x20', NULL ''); 将数据导入reasons。 1 openGauss=# INSERT INTO reasons SELECT * FROM foreign_tpcds_reasons; 父主题: 示例
  • 示例:多线程导入 规划数据服务器与集群处于同一内网,数据服务器IP为192.168.0.90,导入的数据源文件格式为CSV,同时导入2个目标表。 在数据库中创建导入的目标表tpcds.reasons1和tpcds.reasons2。 1 2 3 4 5 6 openGauss=# CREATE TABLE tpcds.reasons1 ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) ; 1 2 3 4 5 6 openGauss=# CREATE TABLE tpcds.reasons2 ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) ; (可选)创建用户及其所属的用户组。此用户用于启动GDS。若该用户及所属用户组已存在,可跳过此步骤。 groupadd gdsgrp useradd -g gdsgrp gds_user 切换用户gds_user,登录GDS数据服务器,创建数据文件存放目录“/input_data”,以及子目录“/input_data/import1/”和“/input_data/import2/”。 su - gds_user mkdir -p /input_data 将目标表tpcds.reasons1的数据源文件存放在数据服务器“/input_data/import1/”目录下,将目标表tpcds.reasons2的数据源文件存放在目录“/input_data/import2/”下。 修改数据服务器上数据文件及数据文件目录“/input_data”的属主为gds_user。 chown -R gds_user:gdsgrp /input_data 以gds_user用户登录数据服务器上启动GDS。 其中GDS安装路径为“/gds”,数据文件存放在“/input_data/”目录下,数据服务器所在IP为192.168.0.90,GDS侦听端口为5000,以后台方式运行,设定并发度为2,并设定递归文件目录。 /gds/gds -d /input_data -p 192.168.0.90:5000 -H 10.10.0.1/24 -D -t 2 -r 在数据库中创建外表tpcds.foreign_tpcds_reasons1和tpcds.foreign_tpcds_reasons2用于接收数据服务器上的数据。 以下以外表tpcds.foreign_tpcds_reasons1为例,讲解设置的导入外表参数信息。 其中设置的导入模式信息如下所示: 导入模式为Normal模式。 由于启动GDS时,设置的数据源文件存放目录为“/input_data/”,GDS侦听端口为5000,实际存放数据源文件目录为“/input_data/import1/”,所以设置参数“location”为“gsfs://192.168.0.90:5000/import1/*”。 设置的数据格式信息是根据导出时设置的详细数据格式参数信息指定的,参数设置如下所示: 数据源文件格式(format)为CSV。 编码格式(encoding)为UTF-8。 字段分隔符(delimiter)为E'\x08'。 引号字符(quote)为0x1b。 数据文件中空值(null)为没有引号的空字符串。 逃逸字符(escape)为默认值双引号。 数据文件是否包含标题行(header)为默认值false,即导入时数据文件第一行被识别为数据。 设置的导入容错性如下所示: 允许出现的数据格式错误个数(PER NODE REJECT LIMIT 'value')为unlimited,即接受导入过程中所有数据格式错误。 将数据导入过程中出现的数据格式错误信息(LOG INTO error_table_name)写入表err_tpcds_reasons1。 当数据源文件中一行的最后一个字段缺失(fill_missing_fields)时,自动设置为NULL。 根据以上信息,创建的外表tpcds.foreign_tpcds_reasons1如下所示: 1 2 3 4 5 6 openGauss=# CREATE FOREIGN TABLE tpcds.foreign_tpcds_reasons1 ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) SERVER gsmpp_server OPTIONS (location 'gsfs://192.168.0.90:5000/import1/*', format 'CSV',mode 'Normal', encoding 'utf8', delimiter E'\x20', quote E'\x1b', null '',fill_missing_fields 'on')LOG INTO err_tpcds_reasons1 PER NODE REJECT LIMIT 'unlimited'; 参考以上设置,创建的外表tpcds.foreign_tpcds_reasons2如下所示: 1 2 3 4 5 6 openGauss=# CREATE FOREIGN TABLE tpcds.foreign_tpcds_reasons2 ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) SERVER gsmpp_server OPTIONS (location 'gsfs://192.168.0.90:5000/import2/*', format 'CSV',mode 'Normal', encoding 'utf8', delimiter E'\x20', quote E'\x1b', null '',fill_missing_fields 'on')LOG INTO err_tpcds_reasons2 PER NODE REJECT LIMIT 'unlimited'; 通过外表tpcds.foreign_tpcds_reasons1和tpcds.foreign_tpcds_reasons2将数据分别导入tpcds.reasons1和tpcds.reasons2。 1 openGauss=# INSERT INTO tpcds.reasons1 SELECT * FROM tpcds.foreign_tpcds_reasons1; 1 openGauss=# INSERT INTO tpcds.reasons2 SELECT * FROM tpcds.foreign_tpcds_reasons2; 查询错误信息表err_tpcds_reasons1和err_tpcds_reasons2,处理数据导入错误。详细请参见处理错误表。 1 2 openGauss=# SELECT * FROM err_tpcds_reasons1; openGauss=# SELECT * FROM err_tpcds_reasons2; 待数据导入完成后,以gds_user用户登录数据服务器,停止GDS。 其中GDS进程号为128954。 ps -ef|grep gds gds_user 128954 1 0 15:03 ? 00:00:00 gds -d /input_data -p 192.168.0.90:5000 -D -t 2 -r gds_user 129003 118723 0 15:04 pts/0 00:00:00 grep gds kill -9 128954
  • 示例:多数据服务器并行导入 规划数据服务器与集群处于同一内网,数据服务器IP为192.168.0.90和192.168.0.91。数据源文件格式为CSV。 创建导入的目标表tpcds.reasons。 1 2 3 4 5 6 openGauss=# CREATE TABLE tpcds.reasons ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ); (可选)创建用户及其所属的用户组。此用户用于启动GDS。若该类用户及所属用户组已存在,可跳过此步骤。 groupadd gdsgrp useradd -g gdsgrp gds_user 切换用户gds_user,登录每台GDS数据服务器,在两台数据服务器上,分别创建数据文件存放目录“/input_data”。以下以IP为192.168.0.90的数据服务器为例进行操作,剩余服务器上的操作与它一致。 su - gds_user mkdir -p /input_data 将数据源文件均匀分发至相应数据服务器的“/input_data”目录中。 修改每台数据服务器上数据文件及数据文件目录“/input_data”的属主为gds_user。以下以IP为192.168.0.90的数据服务器为例,进行操作。 chown -R gds_user:gdsgrp /input_data 以gds_user用户登录每台数据服务器上分别启动GDS。 其中GDS安装路径为“/opt/bin/gds”,数据文件存放在“/input_data/”目录下,数据服务器所在IP为192.168.0.90和192.168.0.91,GDS侦听端口为5000,以后台方式运行。 在IP为192.168.0.90的数据服务器上启动GDS。 /gds/gds -d /input_data -p 192.168.0.90:5000 -H 10.10.0.1/24 -D 在IP为192.168.0.91的数据服务器上启动GDS。 /gds/gds -d /input_data -p 192.168.0.91:5000 -H 10.10.0.1/24 -D 创建外表tpcds.foreign_tpcds_reasons用于接收数据服务器上的数据。 其中设置导入模式信息如下所示: 导入模式为Normal模式。 由于启动GDS时,设置的数据源文件存放目录为“/input_data”,GDS侦听端口为5000,所以设置参数“location”为“gsfs://192.168.0.90:5000/* | gsfs://192.168.0.91:5000/*”。 设置数据格式信息是根据导出时设置的详细数据格式参数信息指定的,参数设置如下所示: 数据源文件格式(format)为CSV。 编码格式(encoding)为UTF-8。 字段分隔符(delimiter)为E'\x08'。 引号字符(quote)为0x1b。 数据文件中空值(null)为没有引号的空字符串。 逃逸字符(escape)为默认值双引号。 数据文件是否包含标题行(header)为默认值false,即导入时数据文件第一行被识别为数据。 设置导入容错性如下所示: 允许出现的数据格式错误个数(PER NODE REJECT LIMIT 'value')为unlimited,即接受导入过程中所有数据格式错误。 将数据导入过程中出现的数据格式错误信息(LOG INTO error_table_name)写入表err_tpcds_reasons。 根据以上信息,创建的外表如下所示: 1 2 3 4 5 6 7 openGauss=# CREATE FOREIGN TABLE tpcds.foreign_tpcds_reasons ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) SERVER gsmpp_server OPTIONS (location 'gsfs://192.168.0.90:5000/* | gsfs://192.168.0.91:5000/*', format 'CSV',mode 'Normal', encoding 'utf8', delimiter E'\x08', quote E'\x1b', null '', fill_missing_fields 'false') LOG INTO err_tpcds_reasons PER NODE REJECT LIMIT 'unlimited'; 通过外表tpcds.foreign_tpcds_reasons,将数据导入目标表tpcds.reasons。 1 openGauss=# INSERT INTO tpcds.reasons SELECT * FROM tpcds.foreign_tpcds_reasons; 查询错误信息表err_tpcds_reasons,处理数据导入错误。详细请参见处理错误表。 1 openGauss=# SELECT * FROM err_tpcds_reasons; 待数据导入完成后,以gds_user用户登录每台数据服务器,分别停止GDS。 以下以IP为192.168.0.90的数据服务器为例,停止GDS。其中GDS进程号为128954。 ps -ef|grep gds gds_user 128954 1 0 15:03 ? 00:00:00 gds -d /input_data -p 192.168.0.90:5000 -D gds_user 129003 118723 0 15:04 pts/0 00:00:00 grep gds kill -9 128954
  • 操作步骤 以gds_user用户登录安装GDS的数据服务器。 请根据启动GDS的方式,选择停止GDS的方式。 若用户使用“gds”命令启动GDS,请使用以下方式停止GDS。 执行如下命令,查询GDS进程号。 ps -ef|grep gds 示例:其中GDS进程号为128954。 ps -ef|grep gds gds_user 128954 1 0 15:03 ? 00:00:00 gds -d /input_data/ -p 192.168.0.90:5000 -l /log/gds_log.txt -D gds_user 129003 118723 0 15:04 pts/0 00:00:00 grep gds 使用“kill”命令,停止GDS。其中128954为上一步骤中查询出的GDS进程号。 kill -9 128954 若用户使用“gds_ctl.py”命令启动GDS,请使用以下命令停止GDS。 cd /opt/bin/gds python3 gds_ctl.py stop
  • 处理数据导入错误 根据获取的错误信息,请对照下表,处理数据导入错误。 表2 处理数据导入错误 错误信息 原因 解决办法 missing data for column "r_reason_desc" 数据源文件中的列数比外表定义的列数少。 对于TEXT格式的数据源文件,由于转义字符(\)导致delimiter(分隔符)错位或者quote(引号字符)错位造成的错误。 示例:目标表存在3列字段,导入的数据如下所示。由于存在转义字符“\”,分隔符“|”被转义为第二个字段的字段值,导致第三个字段值缺失。 BE|Belgium\|1 由于列数少导致的报错,选择下列办法解决: 在数据源文件中,增加列“r_reason_desc”的字段值。 在创建外表时,将参数“fill_missing_fields”设置为“on”。即当导入过程中,若数据源文件中一行数据的最后一个字段缺失,则把最后一个字段的值设置为NULL,不报错。 对由于转义字符导致的错误,需检查报错的行中是否含有转义字符(\)。若存在,建议在创建外表时,将参数“noescaping”(是否不对'\'和后面的字符进行转义)设置为true。 extra data after last expected column 数据源文件中的列数比外表定义的列数多。 在数据源文件中,删除多余的字段值。 在创建外表时,将参数“ignore_extra_data”设置为“on”。即在导入过程中,若数据源文件比外表定义的列数多,则忽略行尾多出来的列。 invalid input syntax for type numeric: "a" 数据类型错误。 在数据源文件中,修改输入字段的数据类型。根据此错误信息,请将输入的数据类型修改为numeric。 null value in column "staff_id" violates not-null constraint 非空约束。 在数据源文件中,增加非空字段信息。根据此错误信息,请增加“staff_id”列的值。 duplicate key value violates unique constraint "reg_id_pk" 唯一约束。 删除数据源文件中重复的行。 通过设置关键字“DISTINCT”,从SELECT结果集中删除重复的行,保证导入的每一行都是唯一的。 1 openGauss=# INSERT INTO reasons SELECT DISTINCT * FROM foreign_tpcds_reasons; value too long for type character varying(16) 字段值长度超过限制。 在数据源文件中,修改字段值长度。根据此错误信息,字段值长度限制为VARCHAR2(16)。
  • 操作步骤 在GaussDB中创建目标表,用于存储导入的数据。建表语句请参见CREATE TABLE。 (可选)若导入表存在索引,在数据导入过程中,将增量更新索引信息,影响数据导入性能。建议在执行数据导入前,先删除相关表的索引。在数据导入完成后,再重新创建索引。 假定在导入表“product_info”上的“product_id”字段上存在普通索引“product_idx”。在执行数据导入前,请先删除相关索引。 1 DROP INDEX product_idx; 在数据导入完成后,重建索引。 1 openGauss=# CREATE INDEX product_idx ON product_info(product_id); 打开enable_stream_operator。 1 openGauss=# set enable_stream_operator=on; 在重建索引过程中,用户可以通过临时增加GUC参数“maintenance_work_mem”/“psort_work_mem”来加快索引的重建。 执行数据导入。 1 openGauss=# INSERT INTO [目标表名] SELECT * FROM [foreign table 表名]; 若出现以下类似信息,说明数据导入成功。请查询错误信息表,查看是否存在数据格式错误,详细操作请参见处理错误表。 INSERT 0 9 若出现数据加载错误,请参见处理错误表,并重新执行数据导入。 若执行过程中出现数据加载错误,则数据全部导入失败,没有数据导入至目标表中。 编写批处理任务脚本,实现并发批量导入数据。并发量视机器资源使用情况而定。可通过几个表测试,监控资源利用率,根据结果提高或减少并发量。常用资源监控命令有:内存和CPU监控top命令,IO监控命令iostat,网络监控命令sar等。相关案例请参见示例:多线程导入。 在资源许可的情况下,多台GDS服务器并发导入会很大程度上提高数据导入效率。相关案例请参见示例:多数据服务器并行导入。 对于高并发的GDS导入场景,为了保持GDS和DN间的数据连接稳定,可以将GDS服务器环境和DN所在环境的TCP Keepalive检测时间增长(推荐增长至5分钟)。调整集群环境的TCP Keepalive参数会影响故障检测的响应时间。 enable_stream_operator=on会影响性能,如果该会话后续还有别的sql执行,建议设置set enable_stream_operator=off,如果没有,则直接断开会话即可。
  • 任务示例 创建一个名为reasons的目标表。 1 2 3 4 5 6 7 openGauss=# CREATE TABLE reasons ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) DISTRIBUTE BY HASH (r_reason_sk); 在执行数据导入前,先删除相关表的索引。在数据导入完成后,再重新创建索引。 假定在导入表“reasons”上的“r_reason_id”字段上存在普通索引“reasons_idx”。在执行数据导入前,请先删除相关索引。 1 openGauss=# DROP INDEX reasons_idx; 在数据导入完成后,重建索引。 1 openGauss=# CREATE INDEX reasons_idx ON reasons(r_reasons_id); 打开enable_stream_operator。 1 openGauss=# set enable_stream_operator=on; 将数据源文件中的数据通过外表“foreign_tpcds_reasons”导入到表“reasons”中。 1 openGauss=# INSERT INTO reasons SELECT * FROM foreign_tpcds_reasons ;
  • 任务示例 除了以下示例,更多外表创建的示例请参考示例。 示例1:创建GDS外表foreign_tpcds_reasons,数据格式为CSV。 1 2 3 4 5 6 7 openGauss=# CREATE FOREIGN TABLE foreign_tpcds_reasons ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) SERVER gsmpp_server OPTIONS (location 'gsfs://192.168.0.90:5000/* | gsfs://192.168.0.91:5000/*', FORMAT 'CSV',MODE 'Normal', ENCODING 'utf8', DELIMITER E'\x20', QUOTE E'\x1b', NULL ''); 示例2:创建GDS导入外表foreign_tpcds_reasons_SSL,使用SSL加密传输的模式传输,数据格式为CSV。 1 2 3 4 5 6 7 openGauss=# CREATE FOREIGN TABLE foreign_tpcds_reasons_SSL ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) SERVER gsmpp_server OPTIONS (location 'gsfss://192.168.0.90:5000/* | gsfss://192.168.0.91:5000/*', FORMAT 'CSV',MODE 'Normal', ENCODING 'utf8', DELIMITER E'\x20', QUOTE E'\x1b', NULL ''); 示例3:创建GDS外表foreign_tpcds_reasons,数据格式为TEXT。 1 2 3 4 5 6 openGauss=# CREATE FOREIGN TABLE foreign_tpcds_reasons ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) SERVER gsmpp_server OPTIONS (location 'gsfs://192.168.0.90:5000/* | gsfs://192.168.0.91:5000/*', FORMAT 'TEXT', delimiter E'\x20', null '',reject_limit '2',EOL '0x0D') WITH err_foreign_tpcds_reasons; 示例4:创建GDS外表foreign_tpcds_reasons,数据格式为FIXED。 1 2 3 4 5 6 openGauss=# CREATE FOREIGN TABLE foreign_tpcds_reasons ( r_reason_sk integer position(1,2), r_reason_id char(16) position(3,16), r_reason_desc char(100) position(19,100) ) SERVER gsmpp_server OPTIONS (location 'gsfs://192.168.0.90:5000/*', FORMAT 'FIXED', ENCODING 'utf8',FIX '119');
  • 操作步骤 收集数据源格式信息、GDS服务的访问信息。 需要收集的主要数据源格式信息如下: format:GDS外表导入支持CSV、TEXT和FIXED格式。请确认存放在数据服务器上待入库数据的格式。例如,假设待入库的数据为CSV格式。 header(仅支持CSV,FIXED格式):确认数据文件是否包含标题行。 delimiter:确认数据文件中,字段间的分隔符。例如,假设是以英文逗号分隔的。 encoding:数据源文件的数据编码格式。例如,假设为UTF-8。 eol:确认数据文件中,行间的换行符。例如,默认的换行符,如0x0D0A、0X0A,或者自定义的换行符,如字符串!@#。该参数仅支持TEXT格式导入。 外表可识别的其他更多格式信息请参见数据格式参数。 需要收集的GDS服务的访问信息如下: location:GDS服务的访问地址。例如以安装配置和启动GDS中的GDS信息为例。非SSL模式下的location为:gsfs://192.168.0.90:5000/input_data/ 。SSL模式下的location为:gsfss://192.168.0.90:5000/input_data/ 。其中,“192.168.0.90:5000”为GDS服务的IP及端口号;“input_data”为GDS服务管理的数据源文件所在的路径。请根据实际情况替换。 依据数据源文件中的数据情况,设计导入容错机制。 GaussDB支持如下的数据容错性处理,相当于数据入库前对数据做初步的简单清洗。 fill_missing_fields:数据入库时,数据源文件中某行的最后一个字段缺失时,请选择是直接将字段设为Null,还是在错误表中报错提示。 ignore_extra_data:数据源文件中的字段比外表定义列数多时,请选择是忽略多出的列,还是在错误表中报错提示。 per node reject_limit:本次数据导入过程中每个DN实例上允许出现的数据格式错误的数量。如果有一个DN实例上录入错误表中的错误数量超过设定值时,本次导入失败,报错退出。可以选择不做限制,也可以根据所能容忍的错误数量选择一个上限值。 compatible_illegal_chars:导入时遇到非法字符,选择如何处理。是将非法字符按照转换规则转换后入库,还是报错中止导入。 非法字符容错转换规则如下: 对于'\0',容错后转换为空格。 对于其他非法字符,容错后转换为问号。 对非法字符进行容错转换时,如遇NULL、DELIMITER、QUOTE、ESCAPE也设置成了空格或问号,GaussDB会通过如"illegal chars conversion may confuse COPY escape 0x20"等报错信息提示用户修改可能引起混淆的参数以避免导入错误。 error_table_name:用于记录数据格式错误信息的错误表表名。并行导入结束后查询此错误信息表,能够获取详细的错误信息。 remote log 'name':数据导入过程中的数据格式错误信息是否同时在GDS服务器上以文件方式保存。name为错误数据文件的文件名前缀。 关于容错性参数的更多信息请参考容错性参数。 使用gsql连接数据库后,根据前面步骤所收集和规划的信息参数,创建GDS外表。 示例如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 openGauss=# CREATE FOREIGN TABLE foreign_tpcds_reasons ( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100) ) SERVER gsmpp_server OPTIONS ( LOCATION 'gsfs://192.168.0.90:5000/input_data | gsfs://192.168.0.91:5000/input_data', FORMAT 'CSV' , DELIMITER ',', ENCODING 'utf8', HEADER 'false', FILL_MISSING_FIELDS 'true', IGNORE_EXTRA_DATA 'true' ) LOG INTO product_info_err PER NODE REJECT LIMIT 'unlimited'; 示例中的各项说明如下: 外表字段需与数据库中即将存储数据的目标表保持一致。 对于GDS导入,SERVER gsmpp_server请保持不变。 location参数请根据1中收集的GDS服务访问信息修改。注意GDS使用SSL加密传输时,需要将“gsfs”替换为“gsfss”。 FORMAT、DELIMITER、ENCODING、HEADER请根据1中收集的数据源格式信息填写。 FILL_MISSING_FIELDS、IGNORE_EXTRA_DATA、LOG INTO及PER NODE REJECT LIMIT请根据2中设计的导入容错机制填写。注意LOG INTO是指将数据格式错误录入哪个错误表,即其取值为错误表表名。 CREATE FOREIGN TABLE语法的更多信息,请参考CREATE FOREIGN TABLE (导入导出)。
  • gds.conf参数说明 表1 gds.conf配置说明 属性 说明 取值范围 name 标识名。 - ip 侦听ip地址。 IP需为合法IP地址。 IP的默认值:127.0.0.1 port 侦听端口号。 取值范围:1024~65535,正整数。 默认值:8098。 data_dir 数据文件目录。 - err_dir 错误日志文件目录。 默认值:数据文件目录 log_file 日志文件路径。 - host 设置允许连接到GDS的主机IP地址(参数为CIDR格式,仅支持linux系统)。 - recursive 是否递归数据文件目录。 取值范围: true:递归 。 false:不递归。 默认值:false。 daemon 是否以DAEMON(后台)模式运行。 取值范围: true:以DAEMON模式运行。 false:不以DAEMON模式运行。 默认值:false。 parallel 导入工作线程并发数目。 取值范围:0~32,正整数。 默认值:1。
共100000条