华为云用户手册

  • 步骤6:优化导入数据的查询性能 在数据导入完成后,执行ANALYZE语句生成表统计信息。执行计划生成器会使用这些统计数据,以生成最有效的查询执行计划。 如果导入过程中,进行了大量的更新或删除行时,应运行VACUUM FULL命令,然后运行ANALYZE命令。大量的更新和删除操作,会产生大量的磁盘页面碎片,从而逐渐降低查询的效率。VACUUM FULL可以将磁盘页面碎片恢复并交还操作系统。 对表product_info执行VACUUM FULL。 1 openGauss=# VACUUM FULL product_info; VACUUM 更新表product_info的统计信息。 1 openGauss=# ANALYZE product_info; ANALYZE 父主题: 教程:使用GDS从远端服务器导入数据
  • 步骤5:分析和处理错误表中的错误信息 对数据导入过程中出现的数据格式错误信息进行处理,若没有错误信息,此步骤可跳过。 查询错误信息。 1 openGauss=# SELECT * FROM product_info_err; 处理错误表中的错误信息。 按照本教程的示例操作,错误表中应该无错误信息。 您也可以将步骤2:在数据服务器上安装配置和启动GDS一节所建外表中的FILL_MISSING_FIELDS和IGNORE_EXTRA_DATA改为'false'后,重新进行数据导入并查询错误表。此时,您将看到因如下原因带来的数据格式错误信息记录: 源数据文件product_info2.csv中第2条记录的最后一个字段“product_comment_content”缺失。 源数据文件product_info2.csv中第3条记录比外表定义列数多。 更多关于错误表及错误信息的处理请参见处理错误表。 父主题: 教程:使用GDS从远端服务器导入数据
  • 步骤4:将数据导入 GaussDB 使用如下语句在GaussDB中创建目标表product_info,用于存储导入的数据。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 openGauss=# DROP TABLE IF EXISTS product_info; openGauss=# CREATE TABLE product_info ( product_price integer not null, product_id char(30) not null, product_time date , product_level char(10) , product_name varchar(200) , product_type1 varchar(20) , product_type2 char(10) , product_monthly_sales_cnt integer , product_comment_time date , product_comment_num integer , product_comment_content varchar(200) ) WITH ( orientation = column, compression=middle ) DISTRIBUTE BY hash (product_id); (可选)本例步骤1中没有创建索引,不用执行这一步。若目标表存在索引,在数据导入过程中,将增量更新索引信息,影响数据导入性能。建议在执行数据导入前,先删除目标表的索引。在数据导入完成后,再重新创建索引。 假定在导入表“product_info”上的“product_id”字段上存在普通索引“product_idx”。在执行数据导入前,请先删除相关索引。 1 openGauss=# 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”来加快索引的重建。 外表的并行导入需要开启stream算子才能够使用。 enable_stream_operator设置为on会影响性能,如果该会话后续还有别的sql执行,建议设置set enable_stream_operator=off,如果没有,则直接断开会话即可。 将数据源文件中的数据通过外表“product_info_ext”导入到表“product_info”中。 1 openGauss=# INSERT INTO product_info SELECT * FROM product_info_ext ; 出现以下信息,说明数据导入成功。 1 INSERT 0 20 执行SELECT命令查询目标表product_info,查看导入到GaussDB中的数据。 1 openGauss=# SELECT count(*) FROM product_info; 查询结果显示结果如下,表示导入成功。 1 2 3 4 count ------- 20 (1 row) 父主题: 教程:使用GDS从远端服务器导入数据
  • 步骤3:在 GaussDB数据库 中创建外表 使用SQL客户端工具连接GaussDB数据库。 根据需要导入数据信息表1,创建如下外表: 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 openGauss=# DROP FOREIGN TABLE IF EXISTS product_info_ext; openGauss=# CREATE FOREIGN TABLE product_info_ext ( product_price integer not null, product_id char(30) not null, product_time date , product_level char(10) , product_name varchar(200) , product_type1 varchar(20) , product_type2 char(10) , product_monthly_sales_cnt integer , product_comment_time date , product_comment_num integer , product_comment_content varchar(200) ) SERVER gsmpp_server OPTIONS( LOCATION 'gsfs://192.168.0.90:5000/*', FORMAT ' CS V' , DELIMITER ',', ENCODING 'utf8', HEADER 'false', FILL_MISSING_FIELDS 'true', IGNORE_EXTRA_DATA 'true' ) READ ONLY LOG INTO product_info_err PER NODE REJECT LIMIT 'unlimited'; 返回如下信息表示创建成功: 1 CREATE FOREIGN TABLE 表1 外表各项的设置说明如下 设置项 值 说明 SERVER gsmpp_server 无需修改,即固定设为gsmpp_server。 LOCATION gsfs://192.168.0.90:5000/* 数据源文件位置。 若使用SSL加密传输时,请使用gsfss协议。即为gsfss://192.168.0.90:5000/* FORMAT CSV 数据源文件格式。 ENCODING UTF-8 数据编码格式。 DELIMITER 英文逗号 字段分隔符。 HEADER false(默认值) 此参数用于指定数据文件是否包含标题行。该参数只针对CSV和FIXED格式的数据文件有效。准备数据源文件中的数据文件第一行不是标题行(即表头),故设为“false”。 FILL_MISSING_FIELDS true 当数据导入时,数据源文件中一行的最后一个字段缺失的处理方式。默认为false/off。本教程中设为“true”。 true/on:表示最后一个字段缺失时,把最后一个字段的值设置为NULL,不报错。 false/off:表示最后一个字段缺失时,做如下报错提示:missing data for column "tt"。 例如,源数据文件product_info2.csv中第2条记录的最后一个字段“product_comment_content”缺失。当FILL_MISSING_FIELDS使用false/off时,导入数据时错误表中会有类似如下的错误信息: missing data for column "product_comment_content" IGNORE_EXTRA_DATA true 数据源文件中的字段比外表定义列数多时,是否忽略多出的列。默认为false/off。本教程中设为“true”。 true/on:数据源文件中字段比外表定义列数多,则忽略行尾多出来的列。不报错 false/off:若数据源文件中字段比外表定义列数多,做如下报错提示:extra data after last expected column。 例如,源数据文件product_info2.csv中第3条记录比外表定义列数多。当IGNORE_EXTRA_DATA设为false/off时,导入数据时错误表中会有类似如下的错误信息: extra data after last expected column PER NODE REJECT LIMIT 'value' unlimited 指定本次数据导入过程中每个DN实例上允许出现的数据格式错误的数量,如果有一个DN实例上的错误数量大于设定值,本次导入失败,报错退出。 本教程设置为“unlimited”,即接受导入过程中所有数据格式错误。 READ ONLY - 外表的语法定义通用于导入数据到GaussDB集群和从集群导出数据。数据导入集群时,请将外表设为READ ONLY;导出时,请设为WRITE ONLY。 WITH error_table_name 错误表名称product_info_err。 数据导入过程中出现的数据格式错误信息将被写入product_info_err指定的错误信息表中,可以在并行导入结束后查询此错误信息表,获取详细的错误信息。 完整的选项说明请见 CREATE FOREIGN TABLE (导入导出)。 父主题: 教程:使用GDS从远端服务器导入数据
  • 获取驱动包 根据不同版本的实例,下载不同版本的发布包,如表1所示。 表1 驱动包下载列表 版本 下载地址 V2.0-8.x 驱动包 驱动包校验包 V2.0-3.x 驱动包 驱动包校验包 V2.0-2.x 驱动包 驱动包校验包 为了防止软件包在传递过程或存储期间被恶意篡改,下载软件包时需下载对应的校验包对软件包进行校验,校验方法如下: 上传软件包和软件包校验包到虚拟机(Linux操作系统)的同一目录下。 执行如下命令,校验软件包完整性。 cat GaussDB_driver.zip.sha256 | sha256sum --check 如果回显OK,则校验通过。 GaussDB_driver.zip: OK
  • 获取驱动包 根据不同版本的实例,下载不同版本的发布包,如表1所示。 表1 驱动包下载列表 版本 下载地址 V2.0-8.x 驱动包 驱动包校验包 V2.0-3.x 驱动包 驱动包校验包 V2.0-2.x 驱动包 驱动包校验包 为了防止软件包在传递过程或存储期间被恶意篡改,下载软件包时需下载对应的校验包对软件包进行校验,校验方法如下: 上传软件包和软件包校验包到虚拟机(Linux操作系统)的同一目录下。 执行如下命令,校验软件包完整性。 cat GaussDB_driver.zip.sha256 | sha256sum --check 如果回显OK,则校验通过。 GaussDB_driver.zip: OK
  • 教程指引 本教程旨在演示使用GDS(Gauss Data Service)工具将远端服务器上的数据导入GaussDB中的办法,帮助您学习如何通过GDS进行数据导入的方法。 在本教程中,您将: 生成本教程需要使用的CSV格式的数据源文件。 将数据源文件上传到数据服务器。 创建外表,用于对接GDS和GaussDB,及将数据服务器上的数据引流到GaussDB集群中。 启动GaussDB并创建数据库表后,将数据导入到表中。 根据错误表中的提示诊断加载错误并更正这些错误。 父主题: 教程:使用GDS从远端服务器导入数据
  • 场景二:常规数据倾斜巡检 在库中表个数少于1W的场景,直接使用倾斜视图查询当前库内所有表的数据倾斜情况。 1 SELECT * FROM pgxc_get_table_skewness ORDER BY totalsize DESC; 在库中表个数非常多(至少大于1W)的场景,因PGXC_GET_TABLE_SKEWNESS涉及全库查并计算非常全面的倾斜字段,所以可能会花费比较长的时间(小时级),建议参考PGXC_GET_TABLE_SKEWNESS视图定义,直接使用table_distribution()函数自定义输出,减少输出列进行计算优化,例如: 1 2 3 4 5 6 SELECT schemaname,tablename,max(dnsize) AS maxsize, min(dnsize) AS minsize FROM pg_catalog.pg_class c INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace INNER JOIN pg_catalog.table_distribution() s ON s.schemaname = n.nspname AND s.tablename = c.relname INNER JOIN pg_catalog.pgxc_class x ON c.oid = x.pcrelid AND x.pclocatortype = 'H' GROUP BY schemaname,tablename;
  • 场景一:磁盘满后快速定位存储倾斜的表 首先,通过pg_stat_get_last_data_changed_time(oid)函数查询出近期发生过数据变更的表,鉴于表的最后修改时间只在进行IUD操作的CN记录,要查询库内1天(间隔可在函数中调整)内被修改的所有表,可以使用如下封装函数: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 CREATE OR REPLACE FUNCTION get_last_changed_table(OUT schemaname text, OUT relname text) RETURNS setof record AS $$ DECLARE row_data record; row_name record; query_str text; query_str_nodes text; BEGIN query_str_nodes := 'SELECT node_name FROM pgxc_node where node_type = ''C'''; FOR row_name IN EXECUTE(query_str_nodes) LOOP query_str := 'EXECUTE DIRECT ON (' || row_name.node_name || ') ''SELECT b.nspname,a.relname FROM pg_class a INNER JOIN pg_namespace b on a.relnamespace = b.oid where pg_stat_get_last_data_changed_time(a.oid) BETWEEN current_timestamp - 1 AND current_timestamp;'''; FOR row_data IN EXECUTE(query_str) LOOP schemaname = row_data.nspname; relname = row_data.relname; return next; END LOOP; END LOOP; return; END; $$ LANGUAGE 'plpgsql'; 然后,通过table_distribution(schemaname text, tablename text)查询出表在各个DN占用的存储空间。 1 SELECT table_distribution(schemaname,relname) FROM get_last_changed_table();
  • 使用方法 设置参数(表倾斜告警阈值table_skewness_warning_threshold和表倾斜告警最小行数table_skewness_warning_rows); 表倾斜告警阈值取值范围0~1,默认值为1,即关闭状态,取其他值时为开启状态。 表倾斜告警最小行数取值范围0~2147483647,默认值为100,000。当导入总行数超过该值与导入DN数之积时,才可能触发告警,从而不会在小数据量导入的场景进行无意义的告警。 1 2 3 4 show table_skewness_warning_threshold; set table_skewness_warning_threshold = xxx; show table_skewness_warning_rows; set table_skewness_warning_rows = xxx; 执行导入,使用INSERT或者COPY; 发现并处理告警,告警信息包括表名、最小行数、最大行数、总行数、平均行数、倾斜率,以及提示信息(检查数据分布或者修改参数)。 WARNING: Skewness occurs, table name: xxx, min value: xxx, max value: xxx, sum value: xxx, avg value: xxx, skew ratio: xxx HINT: Please check data distribution or modify warning threshold
  • 使用gsql元命令导入数据 \copy命令在任何psql客户端登录数据库成功后可以执行导入数据。与COPY命令相比较,\copy命令不是读取或写入指定文件的服务器,而是直接读取或写入文件。 这个操作不如SQL COPY命令有效,因为所有的数据必须通过客户端/服务器的连接来传递。对于大量的数据来说SQL命令可能会更好。 有关如何使用\copy命令的更多信息,请参阅使用gsql元命令导入数据。 \COPY只适合小批量,格式良好的数据导入,不会对非法字符做预处理,也无容错能力,无法适用于含有异常数据的场景。导入数据应优先选择GDS或COPY。
  • 使用INSERT批量插入 带SELECT子句使用批量插入操作来实现高性能数据插入。 如果需要将数据或数据子集从一个表移动到另一个表,可以使用INSERT和CREATE TABLE AS 命令。 如果从指定表插入数据到当前表,例如在数据库中创建了一个表customer_t1的备份表customer_t2,现在需要将表customer_t1中的数据插入到表customer_t2中,则可以执行如下命令。 1 2 3 4 5 6 7 8 openGauss=# CREATE TABLE customer_t2 ( c_customer_sk integer, c_customer_id char(5), c_first_name char(6), c_last_name char(8) ); openGauss=# INSERT INTO customer_t2 SELECT * FROM customer_t1; 上面的示例等价于: 1 openGauss=# CREATE TABLE customer_t2 AS SELECT * FROM customer_t1;
  • 使用INSERT多行插入 如果不能使用COPY命令,而您需要进行SQL插入,可以根据情况使用多行插入。如果您使用的是列存表,一次只插入一行或几行,则数据压缩效率低下。 多行插入是通过批量进行一系列插入而提高性能。下面的示例使用一条INSERT语句向一个三列表插入三行。这仍属于少量插入,只是用来说明多行插入的语法。创建表的步骤请参考创建和管理表。 向表customer_t1中插入多行数据: 1 2 3 4 openGauss=# INSERT INTO customer_t1 VALUES (68, 'a1', 'zhou','wang'), (43, 'b1', 'wu', 'zhao'), (95, 'c1', 'zheng', 'qian'); 有关更多详情和示例,请参阅INSERT 。
  • 使用GDS导入数据 数据倾斜会造成查询表性能下降。对于记录数超过千万条的表,建议在执行全量数据导入前,先导入部分数据,以进行数据倾斜检查和调整分布列,避免导入大量数据后发现数据倾斜,调整成本高。详细请参见查看数据倾斜状态。 为了优化导入速度,建议拆分文件,使用多GDS进行并行导入。另外,单个导入任务可以拆分成多个导入任务并发执行导入,多个导入任务使用同一GDS时可以使用-t参数打开GDS多线程并发执行导入。GDS建议挂载在不同物理盘以及不同网卡上,避免物理IO以及网络可能出现的瓶颈。 为了确保作业的正常运行,请注意根据GDS所承担的负载和并发度,在GDS所在的物理环境上配置充足的系统资源,其中包含但不限于:内存大小、句柄数量、GDS数据目录对应磁盘的空闲空间大小。如果GDS部署于GaussDB集群外部,请确保其物理环境配置与集群内部配置对齐。 在GDS IO与网卡未达到物理瓶颈前,可以考虑在GaussDB开启SMP进行加速。SMP开启之后会对对应的GDS产生成倍的压力。需要特别说明的是:SMP自适应衡量的标准是GaussDB的CPU压力,而不是GDS所承受的压力。 GDS与GaussDB通信要求物理网络畅通,并且尽量使用万兆网。千兆网无法承载高速的数据传输压力,极易出现断连。即使用千兆网时GaussDB无法提供通信保障。满足万兆网的同时,数据磁盘组I/O性能大于GDS单核处理能力上限(约400MB/s)时,方可寻求单文件导入速率最大化。 并发导入场景,与单表导入相似,至少应保证I/O性能大于网络最大速率。 数据服务器上,建议一个Raid只布1~2个GDS。 GDS跟DN的数据比例建议在1:3至1:6之间。 为了优化列存分区表的批量插入效率,在批量插入过程中会对数据进行缓存后再批量写盘。通过GUC参数“partition_mem_batch”和“partition_max_cache_size”,可以设置缓存个数以及缓存区大小。这两个参数的值越小,列存分区表的批量插入越慢。当然,越大的缓存个数和缓存分区,会带来越多的内存消耗。
  • 查看表所在节点 用户在建表时可以指定表如何在节点之间分布或者复制,详情请参考•DISTRIBUTEBY,分布方式介绍可参阅选择分布方式。 用户在建表时也可设置“Node Group”来指定表所在的Group,详情请参考•TO{GROUPgroupname|...。 用户还可以通过以下命令查看表所在实例。 查询表所在的schema。 select t1.nspname,t2.relname from pg_namespace t1,pg_class t2 where t1.oid = t2.relnamespace and t2.relname = 'table1'; 上述命令中,“nspname”为schema的名称,“relname”为表、索引、视图等对象的名称,“oid”为行标识符,“relnamespace”为包含这个关系的名称空间的OID,“table1”为表名称。 查看表的relname和nodeoids。 select t1.relname,t2.nodeoids from pg_class t1, pgxc_class t2, pg_namespace t3 where t1.relfilenode = t2.pcrelid and t1.relnamespace=t3.oid and t1.relname = 'table1' and t3.nspname ='schema1'; 上述命令中,“nodeoids”为表分布的节点OID列表,“relfilenode”为这个关系在磁盘上的文件的名称,“pcrelid”为表的OID,“schema1”为1中查询出的该表所在schema。 根据查询到的表分布的节点,查询表所在实例。 select * from pgxc_node where oid in (nodeoids1, nodeoids2, nodeoids3); 上述命令中的“nodeoids1, nodeoids2, nodeoids3”为2中查询到的3个nodeoids,操作时以实际查询到的为准,各nodeoids间以“,”隔开。 父主题: 表设计最佳实践
  • 选择数据类型 高效数据类型,主要包括以下三方面: 尽量使用执行效率比较高的数据类型 一般来说整型数据运算(包括=、>、<、≧、≦、≠等常规的比较运算,以及group by)的效率比字符串、浮点数要高。比如某客户场景中对列存表进行点查询,filter条件在一个numeric列上,执行时间为10+s;修改numeric为int类型之后,执行时间缩短为1.8s左右。 尽量使用短字段的数据类型 长度较短的数据类型不仅可以减小数据文件的大小,提升IO性能;同时也可以减小相关计算时的内存消耗,提升计算性能。比如对于整型数据,如果可以用smallint就尽量不用int,如果可以用int就尽量不用bigint。 使用一致的数据类型 表关联列尽量使用相同的数据类型。如果表关联列数据类型不同,数据库必须动态地转化为相同的数据类型进行比较,这种转换会带来一定的性能开销。 父主题: 表设计最佳实践
  • 使用分区表 分区表是把逻辑上的一张表根据某种方案分成几张物理块进行存储。这张逻辑上的表称之为分区表,物理块称之为分区。分区表是一张逻辑表,不存储数据,数据实际是存储在分区上的。分区表和普通表相比具有以下优点: 改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索效率。 增强可用性:如果分区表的某个分区出现故障,表在其他分区的数据仍然可用。 方便维护:如果分区表的某个分区出现故障,需要修复数据,只修复该分区即可。 GaussDB支持的分区表为范围分区表。 范围分区表:将数据基于范围映射到每一个分区。这个范围是由创建分区表时指定的分区键决定的。分区键经常采用日期,例如将销售数据按照月份进行分区。 父主题: 表设计最佳实践
  • 选择分布列 Hash分布表的分布列选取至关重要,需要满足以下原则: 列值应比较离散,以便数据能够均匀分布到各个DN。例如,考虑选择表的主键为分布列,如在人员信息表中选择身份证号码为分布列。 在满足上述条件的情况下,考虑选择查询中的连接条件为分布列,以便Join任务能够下推到DN中执行,且减少DN之间的通信数据量。 对于Hash分表策略,如果分布列选择不当,可能导致数据倾斜,查询时出现部分DN的I/O短板,从而影响整体查询性能。因此在采用Hash分表策略之后需对表的数据进行数据倾斜性检查,以确保数据在各个DN上是均匀分布的。可以使用以下SQL检查数据倾斜性 1 2 3 4 5 select xc_node_id, count(1) from tablename group by xc_node_id order by xc_node_id desc; 其中xc_node_id对应DN,一般来说,不同DN的数据量相差5%以上即可视为倾斜,如果相差10%以上就必须要调整分布列。 GaussDB支持多分布列特性,可以更好地满足数据分布的均匀性要求。 Range/List分布表的分布列由用户根据实际需要进行选择。除了需选择合适的分布列,还需要注意分布规则对数据分布的影响。 父主题: 表设计最佳实践
  • 选择分布方式 复制表(Replication)方式将表中的全量数据在集群的每一个DN实例上保留一份。主要适用于记录集较小的表。这种存储方式的优点是每个DN上都有该表的全量数据,在join操作中可以避免数据重分布操作,从而减小网络开销,同时减少了plan segment(每个plan segment都会起对应的线程);缺点是每个DN都保留了表的完整数据,造成数据的冗余。一般情况下只有较小的维度表才会定义为Replication表。 哈希(Hash)表将表中某一个或几个字段进行hash运算后,生成对应的hash值,根据DN实例与哈希值的映射关系获得该元组的目标存储位置。对于Hash分布表,在读/写数据时可以利用各个节点的IO资源,大大提升表的读/写速度。一般情况下大表定义为Hash表。 范围(Range)和列表(List)分布是由用户自定义的分布策略,根据分布列的取值落入满足一定范围或者具体值的对应目标DN,这两种分布方式便于用户灵活地进行数据管理,但对用户本身的数据抽象能力有一定的要求。 策略 描述 适用场景 Hash 表数据通过hash方式散列到集群中的所有DN实例上。 数据量较大的事实表。 Replication 集群中每一个DN实例上都有一份全量表数据。 小表、维度表。 Range 表数据对指定列按照范围进行映射,分布到对应DN。 用户需要自定义分布规则的场景。 List 表数据对指定列按照具体值进行映射,分布到对应DN。 用户需要自定义分布规则的场景。 如图1所示,复制表如图中的表T1,哈希表如图中的表T2。 图1 复制表和哈希表 父主题: 表设计最佳实践
  • 选择存储模型 进行数据库设计时,表设计上的一些关键项将严重影响后续整库的查询性能。表设计对数据存储也有影响:好的表设计能够减少I/O操作及最小化内存使用,进而提升查询性能。 表的存储模型选择是表定义的第一步。客户业务属性是表的存储模型的决定性因素,依据下面表格选择适合当前业务的存储模型。 存储模型 适用场景 行存 点查询(返回记录少,基于索引的简单查询)。 增删改比较多的场景。 列存 统计分析类查询 (group , join多的场景)。 父主题: 表设计最佳实践
  • 数据加载和卸载 【建议】在insert语句中显式给出插入的字段列表。例如: 1 INSERT INTO task(name,id,comment) VALUES ('task1','100','第100个任务'); 【建议】在批量数据入库之后,或者数据增量达到一定阈值后,建议对表进行analyze操作,防止统计信息不准确而导致的执行计划劣化。 【建议】如果要清理表中的所有数据,建议使用truncate table方式,不要使用delete table方式。delete table方式删除性能差,且不会释放那些已经删除了的数据占用的磁盘空间。
  • DDL 【建议】在GaussDB中,建议DDL(建表、comments等)操作统一执行,在批处理作业中尽量避免DDL操作。避免大量并发事务对性能的影响。 【建议】在非日志表(unlogged table)使用完后,立即执行数据清理(truncate)操作。因为在异常场景下,GaussDB不保证非日志表(unlogged table)数据的安全性。 【建议】临时表和非日志表的存储方式建议和基表相同。当基表为行存(列存)表时,临时表和非日志表也推荐创建为行存(列存)表,可以避免行列混合关联带来的高计算代价。 【建议】索引字段的总长度不超过50字节。否则,索引大小会膨胀比较严重,带来较大的存储开销,同时索引性能也会下降。 【建议】不要使用DROP…CASCADE方式删除对象,除非已经明确对象间的依赖关系,以免误删。
  • 连接参数 【关注】第三方工具通过JDBC连接GaussDB时,JDBC向GaussDB发起连接请求,会默认添加以下配置参数,详见JDBC代码ConnectionFactoryImpl类的实现。 params = { { "user", user }, { "database", database }, { "client_encoding", "UTF8" }, { "DateStyle", "ISO" }, { "extra_float_digits", "3" }, { "TimeZone", createPostgresTimeZone() }, }; 这些参数可能会导致JDBC客户端的行为与gsql客户端的行为不一致,例如,Date数据显示方式、浮点数精度表示、timezone显示。 如果实际期望和这些配置不符,建议在java连接设置代码中显式设定这些参数。 【建议】通过JDBC连接数据库时,会设置extra_float_digits=3,gsql中设置为extra_float_digits=0,可能会使同一条数据在JDBC显示和gsql显示的精度不同。 【建议】对于精度敏感的场景,建议使用numeric类型。 【建议】通过JDBC连接数据库时,应该保证下面三个时区设置一致: JDBC客户端所在主机的时区。 GaussDB集群所在主机的时区。 GaussDB集群配置过程中时区。 时区设置相关的操作,请联系管理员。
  • 释放连接 【建议】推荐使用连接池限制应用程序的连接数。每执行一条SQL就连接一次数据库,是一种不好SQL的编写习惯。 【建议】在应用程序完成作业任务之后,应当及时断开和GaussDB的连接,释放资源。建议在任务中设置session超时时间参数。 【建议】使用JDBC连接池,在将连接释放给连接池前,需要执行以下操作,重置会话环境。否则,可能会因为历史会话信息导致的对象冲突。 如果在连接中设置了GUC参数,那么在将连接归还连接池之前,必须使用“SET SESSION AUTHORIZATION DEFAULT;RESET ALL;”将连接的状态清空。 如果使用了临时表,那么在将连接归还连接池之前,必须将临时表删除。
  • 选择数据类型 在字段设计时,基于查询效率的考虑,一般遵循以下原则: 【建议】尽量使用高效数据类型。 选择数值类型时,在满足业务精度的情况下,选择数据类型的优先级从高到低依次为整数、浮点数、NUMERIC。 【建议】当多个表存在逻辑关系时,表示同一含义的字段应该使用相同的数据类型。 【建议】对于字符串数据,建议使用变长字符串数据类型,并指定最大长度。请务必确保指定的最大长度大于需要存储的最大字符数,避免超出最大长度时出现字符截断现象。除非明确知道数据类型为固定长度字符串,否则,不建议使用CHAR(n)、BPCHAR(n)、NCHAR(n)、CHARACTER(n)。 关于字符串类型的详细说明,请参见常用字符串类型介绍。
  • 选择分布键 分布表的分布键选取至关重要,如果分布键选择不当,可能会导致数据倾斜,从而导致查询时,I/O负载集中在部分DN上,影响整体查询性能。因此,在确定分布表的分布策略之后,需要对表数据进行倾斜性检查,以确保数据的均匀分布。分布键的选择一般需要遵循以下原则: 【建议】选作分布键的字段取值应该比较离散,以便数据能在各个DN上均匀分布。当单个字段无法满足离散条件时,可以考虑使用多个字段一起作为分布键。一般情况下,可以考虑选择表的主键作为分布键。例如,在人员信息表中选择证件号码作为分布键。 【建议】在满足第一条原则的情况下,尽量不要选取在查询中存在常量过滤条件的字段作为分布键。例如,在表dwcjk相关的查询中,字段zqdh存在常量过滤条件“zqdh='000001'”,那么就应当尽量不选择zqdh字段做为分布键。 【建议】在满足前两条原则的情况,尽量选择查询中的关联条件为分布键。当关联条件作为分布键时,join任务的相关数据都分布在DN本地,将极大减少DN之间的数据流动代价。
  • 选择分区方案 当表中的数据量很大时,应当对表进行分区,一般需要遵循以下原则: 【建议】使用具有明显区间性的字段进行分区,比如日期、区域等字段上建立分区。 【建议】分区名称应当体现分区的数据特征。例如,关键字+区间特征。 【建议】将分区上边界的分区值定义为MAXVALUE,以防止可能出现的数据溢出。 典型的分区表定义如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CREATE TABLE staffS_p1 ( 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(4,2), MANAGER_ID NUMBER(6), section_ID NUMBER(4) ) PARTITION BY RANGE (HIRE_DATE) ( PARTITION HIRE_19950501 VALUES LESS THAN ('1995-05-01 00:00:00'), PARTITION HIRE_19950502 VALUES LESS THAN ('1995-05-02 00:00:00'), PARTITION HIRE_maxvalue VALUES LESS THAN (MAXVALUE) );
  • 选择分布方案 【建议】表的分布方式的选择一般遵循以下原则: 表2 表的分布方式及使用场景 分布方式 描述 适用场景 Hash 表数据通过Hash方式散列到集群中的所有DN上。 数据量较大的事实表。 Replication 集群中每一个DN都有一份全量表数据。 维度表、数据量较小的事实表。 Range 表数据对指定列按照范围进行映射,分布到对应DN。 用户需要自定义分布规则的场景。 List 表数据对指定列按照具体值进行映射,分布到对应DN。 用户需要自定义分布规则的场景。 当指定Hash、Range或List分布时,创建主键和唯一索引必须包含分布列。 当被参照表指定Hash、Range或List分布时,参照表的外键必须包含分布列。 典型的分布表定义如下: 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 --定义一个表,表中每行存在所有DN中。 CREATE TABLE warehouse_d1 ( W_WAREHOUSE_SK INTEGER NOT NULL, W_WAREHOUSE_ID CHAR(16) NOT NULL, W_WAREHOUSE_NAME VARCHAR(20) , W_WAREHOUSE_SQ_FT INTEGER , W_STREET_NUMBER CHAR(10) , W_STREET_NAME VARCHAR(60) , W_STREET_TYPE CHAR(15) , W_SUITE_NUMBER CHAR(10) , W_CITY VARCHAR(60) , W_COUNTY VARCHAR(30) , W_STATE CHAR(2) , W_ZIP CHAR(10) , W_COUNTRY VARCHAR(20) , W_GMT_OFFSET DECIMAL(5,2) )DISTRIBUTE BY REPLICATION; --定义一个表,使用HASH分布。 CREATE TABLE warehouse_d2 ( W_WAREHOUSE_SK INTEGER NOT NULL, W_WAREHOUSE_ID CHAR(16) NOT NULL, W_WAREHOUSE_NAME VARCHAR(20) , W_WAREHOUSE_SQ_FT INTEGER , W_STREET_NUMBER CHAR(10) , W_STREET_NAME VARCHAR(60) , W_STREET_TYPE CHAR(15) , W_SUITE_NUMBER CHAR(10) , W_CITY VARCHAR(60) , W_COUNTY VARCHAR(30) , W_STATE CHAR(2) , W_ZIP CHAR(10) , W_COUNTRY VARCHAR(20) , W_GMT_OFFSET DECIMAL(5,2), CONSTRAINT W_CONSTR_KEY3 UNIQUE(W_WAREHOUSE_SK) )DISTRIBUTE BY HASH(W_WAREHOUSE_SK); --定义一个表,使用RANGE分布 CREATE TABLE warehouse_d3 ( W_WAREHOUSE_SK INTEGER NOT NULL, W_WAREHOUSE_ID CHAR(16) NOT NULL, W_WAREHOUSE_NAME VARCHAR(20) , W_WAREHOUSE_SQ_FT INTEGER , W_STREET_NUMBER CHAR(10) , W_STREET_NAME VARCHAR(60) , W_STREET_TYPE CHAR(15) , W_SUITE_NUMBER CHAR(10) , W_CITY VARCHAR(60) , W_COUNTY VARCHAR(30) , W_STATE CHAR(2) , W_ZIP CHAR(10) , W_COUNTRY VARCHAR(20) , W_GMT_OFFSET DECIMAL(5,2) )DISTRIBUTE BY RANGE(W_WAREHOUSE_ID) ( SLICE s1 VALUES LESS THAN (10) DATANODE dn1, SLICE s2 VALUES LESS THAN (20) DATANODE dn2, SLICE s3 VALUES LESS THAN (30) DATANODE dn3, SLICE s4 VALUES LESS THAN (MAXVALUE) DATANODE dn4 ); --定义一个表,使用LIST分布 CREATE TABLE warehouse_d4 ( W_WAREHOUSE_SK INTEGER NOT NULL, W_WAREHOUSE_ID CHAR(16) NOT NULL, W_WAREHOUSE_NAME VARCHAR(20) , W_WAREHOUSE_SQ_FT INTEGER , W_STREET_NUMBER CHAR(10) , W_STREET_NAME VARCHAR(60) , W_STREET_TYPE CHAR(15) , W_SUITE_NUMBER CHAR(10) , W_CITY VARCHAR(60) , W_COUNTY VARCHAR(30) , W_STATE CHAR(2) , W_ZIP CHAR(10) , W_COUNTRY VARCHAR(20) , W_GMT_OFFSET DECIMAL(5,2) )DISTRIBUTE BY LIST(W_COUNTRY) ( SLICE s1 VALUES ('USA') DATANODE dn1, SLICE s2 VALUES ('CANADA') DATANODE dn2, SLICE s3 VALUES ('UK') DATANODE dn3, SLICE s4 VALUES (DEFAULT) DATANODE dn4 );
  • Database设计建议 【规则】在实际业务中,根据需要创建新的Database,不建议直接使用集群默认的postgres数据库。 【建议】一个数据库实例内,用户自定义的Database数量推荐值为3个,不建议超过10个。用户自定义的Database数量过多会导致升级、备份等运维操作的效率降低。 【建议】为了适应全球化的需求,使数据库编码能够存储与表示绝大多数的字符,建议创建Database的时候使用UTF-8编码。 【关注】创建Database时,需要重点关注字符集编码(ENCODING)和兼容性(DBCOMPATIBILITY)两个配置项。GaussDB支持TD、ORA、MYSQL和PG四种兼容模式,分别部分兼容Teradata语法、Oracle语法、MySQL语法和PostgreSQL语法,不同兼容模式下的语法行为存在一定差异,默认为MYSQL兼容模式。 【关注】Database的owner默认拥有该Database下所有对象的所有权限,包括删除权限。删除权限影响较大,请谨慎使用。
  • Schema设计建议 【关注】如果该用户不具有sysadmin权限或者不是该Schema的owner,要访问Schema下的对象,需要同时给用户赋予Schema的usage权限和对象的相应权限。 【关注】如果要在Schema下创建对象,需要授予操作用户该Schema的create权限。 【关注】Schema的owner默认拥有该Schema下对象的所有权限,包括删除权限。删除权限影响较大,请谨慎使用。
共100000条