华为云用户手册

  • 选择分布列 Hash分布表的分布列选取至关重要,需要满足以下原则: 列值应比较离散,以便数据能够均匀分布到各个DN。例如,考虑选择表的主键为分布列,如在人员信息表中选择身份证号码为分布列。 在满足第一条原则的情况下尽量不要选取存在常量filter的列。例如,表dwcjk相关的部分查询中出现dwcjk的列zqdh存在常量的约束(例如zqdh=’000001’),那么就应当尽量不用zqdh做分布列。 在满足前两条原则的情况,考虑选择查询中的连接条件为分布列,以便Join任务能够下推到DN中执行,且减少DN之间的通信数据量。 对于Hash分表策略,如果分布列选择不当,可能导致数据倾斜,查询时出现部分DN的I/O短板,从而影响整体查询性能。因此在采用Hash分表策略之后需对表的数据进行数据倾斜性检查,以确保数据在各个DN上是均匀分布的。可以使用以下SQL检查数据倾斜性 12345 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 复制表和哈希表 父主题: 审视和修改表定义
  • 背景信息 ANALYZE语句可收集与数据库中表内容相关的统计信息,统计结果存储在系统表PG_STATISTIC中。查询优化器会使用这些统计数据,以生成最有效的执行计划。 建议在执行了大批量插入/删除操作后,例行对表或全库执行ANALYZE语句更新统计信息。目前默认收集统计信息的采样比例是30000行(即:guc参数default_statistics_target默认设置为100),如果表的总行数超过一定行数(大于1600000),建议设置guc参数default_statistics_target为-2,即按2%收集样本估算统计信息。 对于在批处理脚本或者存储过程中生成的中间表,也需要在完成数据生成之后显式的调用ANALYZE。 对于表中多个列有相关性且查询中有同时基于这些列的条件或分组操作的情况,可尝试收集多列统计信息(当前特性是实验室特性,使用时请联系华为工程师提供技术支持),以便查询优化器可以更准确地估算行数,并生成更有效的执行计划。
  • 审视和修改表定义概述 在分布式框架下,数据分布在各个DN上。一个或者几个DN的数据存在一块物理存储设备上,好的表定义至少需要达到以下几个目标: 表数据均匀分布在各个DN上,以防止单个DN对应的存储设备空间不足造成集群有效容量下降。选择合适分布列,避免数据分布倾斜可以实现该点。 表Scan压力均匀分散在各个DN上,以避免单DN的Scan压力过大,形成Scan的单节点瓶颈。分布列不选择基表上等值filter中的列可以实现该点。 减少扫描数据量。通过分区的剪枝机制可以实现该点。 尽量极少随机IO。通过聚簇/局部聚簇可以实现该点。 尽量避免数据shuffle,减小网络压力。通过选择join-condition或者group by列为分布列可以最大程度的实现这点。 从上述描述来看表定义中最重要的一点是分布列的选择。创建表定义一般遵循图1所示流程。表定义在数据库设计阶段创建,在SQL调优过程中进行审视和修改。 图1 表定义流程 父主题: 审视和修改表定义
  • 选择存储模型 进行数据库设计时,表设计上的一些关键项将严重影响后续整库的查询性能。表设计对数据存储也有影响:好的表设计能够减少I/O操作及最小化内存使用,进而提升查询性能。 表的存储模型选择是表定义的第一步。客户业务属性是表的存储模型的决定性因素,依据下面表格选择适合当前业务的存储模型。 存储模型 适用场景 行存 点查询(返回记录少,基于索引的简单查询)。 增删改比较多的场景。 列存 统计分析类查询 (group , join多的场景)。 父主题: 审视和修改表定义
  • 调优手段之统计信息 GaussDB优化器是典型的基于代价的优化 (Cost-Based Optimization,简称CBO)。在这种优化器模型下,数据库根据表的元组数、字段宽度、NULL记录比率、distinct值、MCV值、HB值等表的特征值,以及一定的代价计算模型,计算出每一个执行步骤的不同执行方式的输出元组数和执行代价(cost),进而选出整体执行代价最小/首元组返回代价最小的执行方式进行执行。这些特征值就是统计信息。从上面描述可以看出统计信息是查询优化的核心输入,准确的统计信息将帮助规划器选择最合适的查询规划,一般来说我们通过analyze语法收集整个表或者表的若干个字段的统计信息,周期性地运行ANALYZE,或者在对表的大部分内容做了更改之后马上运行它是个好习惯。
  • 调优手段之GUC参数 查询优化的主要目的是为查询语句选择高效的执行方式。 如下SQL语句: 12 select count(1) from customer inner join store_sales on (ss_customer_sk = c_customer_sk); 在执行customer inner join store_sales的时候,GaussDB支持Nested Loop、Merge Join和Hash Join三种不同的Join方式。优化器会根据表customer和表store_sales的统计信息估算结果集的大小以及每种join方式的执行代价,然后对比选出执行代价最小的执行计划。 正如前面所说,执行代价计算都是基于一定的模型和统计信息进行估算,当因为某些原因代价估算不能反映真实的cost的时候,我们就需要通过guc参数设置的方式让执行计划倾向更优规划。
  • 操作步骤 收集SQL中涉及到的所有表的统计信息。在数据库中,统计信息是规划器生成计划的源数据。没有收集统计信息或者统计信息陈旧往往会造成执行计划严重劣化,从而导致性能问题。从经验数据来看,10%左右性能问题是因为没有收集统计信息。具体请参见更新统计信息。 通过查看执行计划来查找原因。如果SQL长时间运行未结束,通过EXPLAIN命令查看执行计划,进行初步定位。如果SQL可以运行出来,则推荐使用EXPLAIN ANALYZE或EXPLAIN PERFORMANCE查看执行计划及实际运行情况,以便更精准地定位问题原因。有关执行计划的详细介绍请参见SQL执行计划介绍。 审视和修改表定义。 针对EXPLAIN或EXPLAIN PERFORMANCE信息,定位SQL慢的具体原因以及改进措施,具体参见典型SQL调优点。 通常情况下,有些SQL语句可以通过查询重写转换成等价的,或特定场景下等价的语句。重写后的语句比原语句更简单,且可以简化某些执行步骤达到提升性能的目的。查询重写方法在各个数据库中基本是通用的。经验总结:SQL语句改写规则介绍了几种常用的通过改写SQL进行调优的方法。
  • 执行计划显示格式 GaussDB对执行计划提供了normal、pretty、summary、run四种显示格式: normal:代表使用默认的打印格式。图1中即为此显示格式。 pretty:代表使用GaussDB改进后的新显示格式。新的格式层次清晰,计划包含了plan node id,性能分析简单直接。如图2。 summary:是在pretty的基础上增加了对打印信息的分析。 run:在summary的基础上,将统计的信息输出到csv格式的文件中,以便于进一步分析。
  • 执行计划显示信息 除了设置不同的执行计划显示格式外,还可以通过不同的EXPLAIN用法,显示不同详细程度的执行计划信息。常见有如下几种,关于更多用法请参见EXPLAIN语法说明。 EXPLAIN statement: 只生成执行计划,不实际执行。其中statement代表SQL语句。 EXPLAIN ANALYZE statement:生成执行计划,进行执行,并显示执行的概要信息。显示中加入了实际的运行时间统计,包括在每个规划节点内部花掉的总时间(以毫秒计)和它实际返回的行数。 EXPLAIN PERFORMANCE statement:生成执行计划,进行执行,并显示执行期间的全部信息。 为了测量运行时在执行计划中每个节点的开销,EXPLAIN ANALYZE或EXPLAIN PERFORMANCE会在当前查询执行上增加性能分析的开销。在一个查询上运行EXPLAIN ANALYZE或EXPLAIN PERFORMANCE有时会比普通查询明显的花费更多的时间。超支的数量依赖于查询的本质和使用的平台。 因此,当定位SQL运行慢问题时,如果SQL长时间运行未结束,建议通过EXPLAIN命令查看执行计划,进行初步定位。如果SQL可以运行出来,则推荐使用EXPLAIN ANALYZE或EXPLAIN PERFORMANCE查看执行计划及其实际的运行信息,以便更精准地定位问题原因。
  • 操作步骤 参考连接数据库,连接数据库。 查看阻塞的查询语句及阻塞查询的表、模式信息。 1 2 3 4 5 6 7 8 91011 SELECT w.query as waiting_query,w.pid as w_pid,w.usename as w_user,l.query as locking_query,l.pid as l_pid,l.usename as l_user,t.schemaname || '.' || t.relname as tablenamefrom pg_stat_activity w join pg_locks l1 on w.pid = l1.pidand not l1.granted join pg_locks l2 on l1.relation = l2.relationand l2.granted join pg_stat_activity l on l2.pid = l.pid join pg_stat_user_tables t on l1.relation = t.relidwhere w.waiting; 该查询返回线程ID、用户信息、查询状态,以及导致阻塞的表、模式信息。 使用如下命令结束相应的会话。其中,139834762094352为线程ID。 1 SELECT PG_TERMINATE_BACKEND(139834762094352); 显示类似如下信息,表示结束会话成功。 PG_TERMINATE_BACKEND---------------------- t(1 row) 显示类似如下信息,表示用户正在尝试结束当前会话。 FATAL: terminating connection due to administrator commandFATAL: terminating connection due to administrator command 1. gsql客户端使用PG_TERMINATE_BACKEND函数结束当前正在执行会话的后台线程时,如果当前的用户是初始用户,客户端不会退出而是自动重连,即还会返回“The connection to the server was lost. Attempting reset: Succeeded.”;否则客户端会重连失败,即返回“The connection to the server was lost. Attempting reset: Failed.”。这是因为只有初始用户可以免密登录,普遍用户不能免密登录,从而重连失败。 2. 对于使用PG_TERMINATE_BACKEND函数结束非活跃的后台线程时。如果打开了线程池,此时空闲的会话没有线程ID,无法结束会话。非线程池模式下,结束的会话不会自动重连。
  • 调优范围确定 性能调优主要通过查看集群各节点的CPU、内存、I/O和网络这些硬件资源的使用情况,确认这些资源是否已被充分利用,是否存在瓶颈点,然后针对性调优。 如果某个资源已达瓶颈,则: 检查关键的操作系统参数和数据库参数是否合理设置。 通过查询最耗时的SQL语句、跑不出来的SQL语句,找出耗资源的SQL,进行SQL调优指南。 如果所有资源均未达瓶颈,则表明性能仍有提升潜力。可以查询最耗时的SQL语句,或者跑不出来的SQL语句,进行针对性的SQL调优指南。
  • SQL调优指南 SQL调优的唯一目的是“资源利用最大化”,即CPU、内存、磁盘IO、网络IO四种资源利用最大化。所有调优手段都是围绕资源使用开展的。所谓资源利用最大化是指SQL语句尽量高效,节省资源开销,以最小的代价实现最大的效益。比如做典型点查询的时候,可以用seqscan+filter(即读取每一条元组和点查询条件进行匹配)实现,也可以通过indexscan实现,显然indexscan可以以更小的代价实现相同的效果。 根据硬件资源和客户的业务特征确定合理的集群部署方案和表定义是数据库在多数情况下满足性能要求的基础。下文的调优说明假设您已根据“软件安装”指引在安装过程中按照合理的集群方案完成了安装,且已经根据“开发设计建议”的指引进行了数据库设计。 Query执行流程 SQL执行计划介绍 调优流程 更新统计信息 审视和修改表定义 典型SQL调优点 经验总结:SQL语句改写规则 SQL调优关键参数调整 使用Plan Hint进行调优 检查隐式转换的性能问题 使用向量化执行引擎进行调优 父主题: 性能调优
  • 性能因素 多个性能因素会影响数据库性能,了解这些因素可以帮助定位和分析性能问题。 系统资源 数据库性能在很大程度上依赖于磁盘的I/O和内存使用情况。为了准确设置性能指标,用户需要了解集群部署硬件的基本性能。CPU,硬盘,磁盘控制器,内存和网络接口等这些硬件性能将显著影响数据库的运行速度。 负载 负载等于数据库系统的需求总量,它会随着时间变化。总体负载包含用户查询,应用程序,并行作业,事务以及数据库随时传递的系统命令。比如:多用户在执行多个查询时会提高负载。负载会显著地影响数据库的性能。了解工作负载高峰期可以帮助用户更合理地利用系统资源,更有效地完成系统任务。 吞吐量 使用系统的吞吐量来定义处理数据的整体能力。数据库的吞吐量以每秒的查询次数、每秒的处理事务数量或平均响应时间来测量。数据库的处理能力与底层系统(磁盘I/O,CPU速度,存储器带宽等)有密切的关系,所以当设置数据库吞吐量目标时,需要提前了解硬件的性能。 竞争 竞争是指两组或多组负载组件尝试使用冲突的方式使用系统的情况。比如,多条查询视图同一时间更新相同的数据,或者多个大量的负载争夺系统资源。随着竞争的增加,吞吐量下降。 优化 数据库优化可以影响到整个系统的性能。在执行SQL制定、数据库配置参数、表设计、数据分布等操作时,启用数据库查询优化器打造最有效的执行计划。
  • 操作步骤 根据规划导出数据中规划的路径确定外表参数location的值。 Remote模式 请通过URL方式设置参数“location”,用于指定导出的数据文件存放路径。 不需要指定文件名。 当有多个路径时,只有第一个路径有效。 示例: GDS数据服务器IP为192.168.0.90,假定启动GDS时设置的侦听端口为5000,设置的导出后文件存放目录为“/output_data/”。 根据以上情况,在创建外表时,指定参数“location”为“gsfs://192.168.0.90:5000/”。 Local模式 设置参数“location”,用于指定导出的数据文件存放路径,不需要指定文件名。 示例: 数据源文件可通过本地文件方式访问,计划将导出数据文件存放在“/output_data/”目录中。 根据以上情况,在创建外表时,指定参数“location”为“file:///output_data/”。 梳理待导出数据的格式信息,确定创建外表时使用的数据格式参数的值。格式参数详细介绍,请参见数据格式参数。 根据前面步骤确定的参数,创建GDS外表。外表的创建语法以及详细使用,请参考CREATE FOREIGN TABLE (导入导出)。
  • 示例 示例1:创建GDS导出外表foreign_tpcds_reasons,待导出数据格式为CSV,用于接收数据服务器上的数据。 其中设置的导出模式信息如下所示: 规划数据服务器与集群处于同一内网,数据服务器IP为192.168.0.90,待导出的数据文件格式为CSV,选择并行导出模式为Remote模式。 假定启动GDS时,规划导出的数据文件存放目录为“/output_data/”,GDS侦听端口为5000,所以设置参数“location”为“gsfs://192.168.0.90:5000/”。 设置导出的数据格式信息,参数设置如下所示: 导出数据文件格式(format)为CSV。 编码格式(encoding)为UTF-8。 字段分隔符(delimiter)为E'\x20'。 引号字符(quote)为0x1b。 数据文件中空值(null)为没有引号的空字符串。 逃逸字符(escape)为默认值双引号。 数据文件是否包含标题行(header)为默认值false,即导出时数据文件第一行被识别为数据。 导出数据文件换行符样式(EOL)为0X0A。 创建的外表如下所示: 1 2 3 4 5 6 7 8 9101112131415 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/', FORMAT 'CSV',DELIMITER E'\x20',QUOTE E'\x1b', NULL '', EOL '0x0a')WRITE ONLY; 示例2:创建GDS导出外表foreign_tpcds_reasons,导出数据格式为FIXED,用于接收数据服务器上的数据。 其中设置的导出模式信息如下所示: 规划数据服务器与集群处于同一内网,数据服务器IP为192.168.0.90,计划导出的数据文件格式为CSV,选择并行导出模式为Remote模式。 假定启动GDS时,规划导出的数据文件存放目录为“/output_data/”,GDS侦听端口为5000,所以设置参数“location”为“gsfs://192.168.0.90:5000/”。 设置导出的数据格式信息,参数设置如下所示: 导出数据文件格式(format)为FIXED。 编码格式(encoding)为UTF-8。 数据文件是否包含标题行(header)为默认值false,即指定导出数据文件是不包含标题行。 定义每一个字段在数据文件中的位置POSITION(offset,length)。其中offset为该字段在文件中的起始位置,length为该字段的长度,单位为字节。 字段“r_reason_sk”,数据类型为integer,使用以下查询所得占用的最大字节数为2,所以设置的起始位置为1,长度为2。 字段“r_reason_id”,数据类型为character varying(16),使用以下查询所得占用的最大字节数为16,所以设置的起始位置为字段“r_reason_sk”的offset+length=1+2=3,长度为16。 字段“r_reason_desc”,数据类型为character varying(100),使用以下查询所得占用的最大字节数为100,所以设置的起始位置为字段“r_reason_id”的offset+length=3+16=19,长度为100。 12345 openGauss=# SELECT max(lengthb(r_reason_sk)),max(lengthb(r_reason_id)),max(lengthb(r_reason_desc)) FROM reasons; max | max | max -----+-----+----- 2 | 16 | 100(1 row) 导出数据文件换行符样式(EOL)为0X0A。 创建的外表如下所示: 1 2 3 4 5 6 7 8 9101112 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',EOL '0x0a')WRITE ONLY;
  • 调优流程 调优流程如图1所示。 图1 GaussDB性能调优流程 调优各阶段说明,如表1所示。 表1 GaussDB性能调优流程说明 阶段 描述 确定性能调优范围 获取集群各节点的CPU、内存、I/O和网络资源使用情况,确认这些资源是否已被充分利用,是否存在瓶颈点。 SQL调优指南 审视业务所用SQL语句是否存在可优化空间,包括: 通过ANALYZE语句生成表统计信息:ANALYZE语句可收集与数据库中表内容相关的统计信息,统计结果存储在系统表PG_STATISTIC中。执行计划生成器会使用这些统计数据,以确定最有效的执行计划。 分析执行计划:EXPLAIN语句可显示SQL语句的执行计划,EXPLAIN PERFORMANCE语句可显示SQL语句中各算子的执行时间。 查找问题根因并进行调优:通过分析执行计划,找到可能存在的原因,进行针对性的调优,通常为调整数据库级SQL调优参数。 编写更优的SQL:介绍一些复杂查询中的中间临时数据缓存、结果集缓存、结果集合并等场景中的更优SQL语法。
  • 相关概念 数据文件:存储有数据的TEXT、CSV或FIXED文件。文件中保存的是从GaussDB数据库导出的数据。 外表:用于规划导出数据文件的数据文件格式、存放位置、编码格式等信息。 GDS:数据服务工具。在导出数据时,需要将此工具部署到数据文件所在的服务器上,使DN可以通过该工具导出数据。 表:数据库中的表,包括行存表和列存表。数据文件中的数据从这些表中导出。 Local导出模式:将集群中的业务数据导出到集群节点所在主机上。 Remote导出模式:将集群中的业务数据导出到集群之外的主机上。
  • 导出流程 图2 并行导出流程 表1 流程说明 流程 说明 子任务 规划导出数据。 根据所选模式,准备需要导出的数据并规划导出路径。 详细内容请参见规划导出数据 - 是否为Local模式? 根据创建外表时所规划的导出模式判断,是否为Local模式。 - 启动GDS。 若规划的导出模式为Remote模式,需在数据服务器上安装配置并启动GDS。 详细内容请参见安装配置和启动GDS。 - 创建外表。 创建外表用于帮助GDS指定导出的数据文件。外表中保存了导出数据文件的位置、文件格式、编码格式、数据间的分隔符等信息。 详细内容请参见创建GDS外表。 - 执行导出数据。 在创建好外表后,通过INSERT语句,将数据快速、高效地导出到数据文件中。 详细内容请参见执行导出数据。 - 停止GDS。 数据导出完成后,停止GDS。 详细请参见停止GDS。 -
  • 操作步骤 分析数据源特征,选择若干个键值重复度小,数据分布比较均匀的备选分布列。 从步骤1中选择一个备选分布列创建目标表。 1 2 3 4 5 6 7 8 910111213 CREATE [ [ GLOBAL | LOCAL ] [ TEMPORARY | TEMP ] | UNLOGGED ] 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 REFERENCES 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。 (可选)如果上述步骤不能选出适合的分布列,需要从备选分布列选择多个列的组合作为分布列来完成数据迁移。
  • 示例 对目标表staffs选择合适的分布列。 分析表staffs的数据源特征,选择数据重复度低且分布均匀的备选分布列staff_ID、FIRST_NAME和LAST_NAME。 先选择staff_ID作为分布列,创建目标表staffs。 1 2 3 4 5 6 7 8 9101112131415 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条。 12345 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 9101112 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 | datanode410000 | datanode312001 | datanode2 8995 | datanode110000 | datanode5 7999 | datanode6 9995 | datanode710000 | 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 9101112131415 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 9101112 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 | datanode410000 | datanode310001 | datanode2 9995 | datanode110000 | datanode5 9999 | datanode6 9995 | datanode710000 | datanode8(8 rows) 根据上一步骤查询所得,各DN上数据分布差小于10%,数据分布均衡,选择的分布列合适。 清理已导入小批量数据。 1 openGauss=# TRUNCATE TABLE staffs; 导入全量数据,以完成数据迁移。
  • 背景信息 GaussDB是采用Shared-Nothing架构的MPP(Massive Parallel Processor,大规模并发处理)系统,采用水平分布的方式,将业务数据表的元组按合适的分布策略分散存储在所有的DN。 当前产品支持复制(Replication)、散列(Hash)、范围(Range)和列表(List)等多种用户表分布策略。 Replication方式:在每一个DN上存储一份全量表数据。对于数据量比较小的表建议采取Replication分布策略。 Hash方式:采用这种分布方式,需要为用户表指定一个分布列(distribute key)。当插入一条记录时,系统会根据分布列的值进行hash运算后,将数据存储在对应的DN中。对于数据量比较大的表建议采取Hash分布策略。 Range方式和List方式:用于用户指定数据分布规则的场景,根据指定字段取值与预先设定的范围或具体值来确定该元组的目标节点。
  • 任务示例 示例1:将表reasons的数据通过外表foreign_tpcds_reasons导出到数据文件中。 1 openGauss=# INSERT INTO foreign_tpcds_reasons SELECT * FROM reasons; 示例2:通过条件过滤(r_reason_sk =1),向数据文件中导出部分数据。 1 openGauss=# INSERT INTO foreign_tpcds_reasons SELECT * FROM reasons WHERE r_reason_sk=1; 示例3:对于特殊的数据类型如RAW类型,在导出之后是一个二进制文本,导入工具无法识别。需使用RAWTOHEX()函数将其转换为16进制文本导出。 1 openGauss=# INSERT INTO foreign_blob_type_tab SELECT RAWTOHEX(c) FROM blob_type_tab;
  • 操作步骤 执行数据导出。 1 INSERT INTO [foreign table 表名] SELECT * FROM [源表名]; 编写批处理任务脚本,实现并发批量导出数据。并发量视机器资源使用情况而定。可通过几个表测试,监控资源利用率,根据结果提高或减少并发量。常用资源监控命令有:内存和CPU监控top命令,IO监控命令iostat,网络监控命令sar等。 仅支持单个内表导出,不支持多表Join联合导出,不支持单表的聚集、排序、子查询、limit等操作结果导出。 本版本中GDS导出已经支持CN RETRY(当前特性是实验室特性,使用时请联系华为工程师提供技术支持),当出现DN故障或者GTM故障导致的网络错误发生时会触发CN RETRY。注意要保证GDS 和内核版本一致或者都高于此版本。
  • 规划导出路径 Remote模式 (可选)创建用户及所属的用户组。此用户为启动GDS的用户,该用户需要拥有导出数据文件存放目录的写权限。 groupadd gdsgrpuseradd -g gdsgrp gdsuser 若出现以下提示,说明数据库用户及所属用户组已存在,可跳过本步骤。 useradd: Account 'gdsuser' already exists.groupadd: Group 'gdsgrp' already exists. 创建导出的数据文件存放目录“/output_data”。 mkdir -p /output_data 修改数据文件目录属主为gdsuser。 chown -R gdsuser:gdsgrp /output_data Local模式 在集群的每个DN上创建导出数据文件存放目录“/output_data”。 mkdir -p /output_data 修改数据文件目录属主为omm。 chown -R omm:dbgrp /output_data 将参数“location”设为本地路径,不需要指定文件名。 例如:计划将导出数据文件存放在“/output_data/”目录中。 根据以上情况,在创建外表时,指定参数“location”为“file:///output_data/”。
  • 相同表的并发INSERT 事务T1: 123 START TRANSACTION;INSERT INTO test VALUES(2,'test2','test123');COMMIT; 事务T2: 123 START TRANSACTION;INSERT INTO test VALUES(3,'test3','test123');COMMIT; 场景1: 开启事务T1,不提交的同时开启事务T2,事务T1执行INSERT完成后,执行事务T2的INSERT语句,可以执行成功,读已提交和可重复读隔离级别下,此时在事务T1中执行SELECT语句,看不到事务T2中插入的数据,事务T2中执行查询语句看不到事务T1中插入的数据。 场景2: READ COMMITTED级别 开启事务T1,不提交的同时开启事务T2,事务T1执行INSERT完成后直接提交,事务T2中执行INSERT语句后执行查询语句,可以看到事务T1中插入的数据。 REPEATABLE READ级别 开启事务T1,不提交的同时开启事务T2,事务T1执行INSERT完成后直接提交,事务T2中执行INSERT语句后执行查询语句,看不到事务T1中插入的数据。 父主题: 并发写入示例
  • 数据导入和查询的并发 事务T1: 123 START TRANSACTION;COPY test FROM '...';COMMIT; 事务T2: 123 START TRANSACTION;SELECT * FROM test;COMMIT; 场景1: 开启事务T1,不提交的同时开启事务T2,事务T1开始执行COPY,事务T2开始执行SELECT,事务T1和事务T2都执行成功。事务T2中查询看不到事务T1新COPY进来的数据。 场景2: READ COMMITTED级别 开启事务T1,不提交的同时开启事务T2,事务T1开始执行COPY,然后提交,事务T2查询,可以看到事务T1中COPY的数据。 REPEATABLE READ级别 开启事务T1,不提交的同时开启事务T2,事务T1开始执行COPY,然后提交,事务T2 查询,看不到事务T1中COPY的数据。 父主题: 并发写入示例
  • 示例:多线程导入 规划数据服务器与集群处于同一内网,数据服务器IP为192.168.0.90,导入的数据源文件格式为CSV,同时导入2个目标表。 在数据库中创建导入的目标表tpcds.reasons1和tpcds.reasons2。 123456 openGauss=# CREATE TABLE tpcds.reasons1( r_reason_sk integer not null, r_reason_id char(16) not null, r_reason_desc char(100)) ; 123456 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 gdsgrpuseradd -g gdsgrp gds_user 切换用户gds_user,登录GDS数据服务器,创建数据文件存放目录“/input_data”,以及子目录“/input_data/import1/”和“/input_data/import2/”。 su - gds_usermkdir -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如下所示: 123456 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如下所示: 123456 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,处理数据导入错误。详细请参见处理错误表。 12 openGauss=# SELECT * FROM err_tpcds_reasons1;openGauss=# SELECT * FROM err_tpcds_reasons2; 待数据导入完成后,以gds_user用户登录数据服务器,停止GDS。 其中GDS进程号为128954。 ps -ef|grep gdsgds_user 128954 1 0 15:03 ? 00:00:00 gds -d /input_data -p 192.168.0.90:5000 -D -t 2 -rgds_user 129003 118723 0 15:04 pts/0 00:00:00 grep gdskill -9 128954
  • 示例:多数据服务器并行导入 规划数据服务器与集群处于同一内网,数据服务器IP为192.168.0.90和192.168.0.91。数据源文件格式为CSV。 创建导入的目标表tpcds.reasons。 123456 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 gdsgrpuseradd -g gdsgrp gds_user 切换用户gds_user,登录每台GDS数据服务器,在两台数据服务器上,分别创建数据文件存放目录“/input_data”。以下以IP为192.168.0.90的数据服务器为例进行操作,剩余服务器上的操作与它一致。 su - gds_usermkdir -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。 根据以上信息,创建的外表如下所示: 1234567 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 gdsgds_user 128954 1 0 15:03 ? 00:00:00 gds -d /input_data -p 192.168.0.90:5000 -Dgds_user 129003 118723 0 15:04 pts/0 00:00:00 grep gdskill -9 128954
  • 相同表的并发UPDATE 事务T1: 123 START TRANSACTION;UPDATE test SET address='test1234' WHERE name='test1';COMMIT; 事务T2: 123 START TRANSACTION;UPDATE test SET address='test1234' WHERE name='test2';COMMIT; 事务T3: 123 START TRANSACTION;UPDATE test SET address='test1234' WHERE name='test1';COMMIT; 场景1: 开启事务T1,不提交的同时开启事务T2,事务T1开始执行UPDATE,事务T2开始执行UPDATE,事务T1和事务T2都执行成功。更新不同行时,更新操作拿的是行级锁,不会发生冲突,两个事务都可以执行成功。 场景2: 开启事务T1,不提交的同时开启事务T3,事务T1开始执行UPDATE,事务T3开始执行UPDATE,事务T1执行成功,事务T3等待超时后会出错。更新相同行时,事务T1未提交时,未释放锁,导致事务T3执行不成功。 父主题: 并发写入示例
共100000条