开发指南

基于云原生数据库,构建您的数据仓库系统。

本文档详细介绍在 HashData 云数仓上进行数据开发时的建议,以规范基于 HashData 数据库平台的应用开发,提高开发质量。主要包含 HashData 数据库用户使用及应用开发的规范要求, 适合以下人员:

  • 数据库系统管理及运维人员
  • 数据库应用涉及的开发人员

开发指南主要包括以下内容:

  • 全局对象设计规范
  • 非全局对象设计规范
  • 数据库访问规范
  • 开发规范
  • 运行规范

全局对象申请规范

在共享元数据集群的场景下,所有计算集群共享数据库的全局对象。数据库所有全局对象均需通过DBA创建,应用需提交服务请求需求调查表,按规范配置数据库全局对象,由DBA通过变更实施创建。全局对象申请规范,可创建对象包括但不限于:

  • 表空间
  • Schema
  • 资源队列
  • 资源组
  • 用户组
  • 用户

表空间申请规范

对象存储单个bucket并发吞吐能力有限,表空间用于确保每个对象存储bucket下的文件数目不会过多,防止同一bucket的文件数过多造成操作性能下降。

命名规范

表空间命名长度不能超过60个字符,命名格式为:tbs_{数据区名称}_{应用名}_{序号}

例如:贴源base加工应用的表空间命名为:tbs_base_sor_01。数据区命名规则如下所示:

  • stage:登陆区,存放日常加载数据,原则上只保留 3 天数据
  • base: 贴源区,存放贴源加工结果数据
  • ngadw:公共访问区(核心应用),存放访问数据
  • ngapp:公共访问区(仓外应用),存放访问数据
  • tmp: 临时区,存放临时数据,用后可清理
  • app: 应用区,存放应用加工结果数据
  • lds:应用区(实验),存放实验区结果
  • hds:应用区(归档),存放历史归档数据
  • fidi:云化数仓应用区
  • fidi_mgr:云化数仓临时区
  • fida:云化数仓访问区

申请规范

  • 单个表空间表数据量不能超过5万张,数据量不能超过500TB;
  • 共享元数据集群架构下,申请表空间必须填写所属应用、用途描述
  • 申请表空间需填写:表空间预计表数量、预计数据量,用于规划对象存储bucket拆分,每5000张/50TB数据对应一个bucket。

Schema申请规范

Schema用于对表、视图等对象进行分类管理。

命名规范

  • Schema 总长度不得超过 30 个字符;
  • 数据表 Schema 命名格式为:t_{数据区名称}_{应用名}_{可扩展字段}
  • 视图 Schema 命名格式为:v_{数据区名称V}_{应用名}_{可扩展字段}
  • 应用名采用缩写方式,控制在 5个字符内;
  • 如果是全局表,可不使用应用名;
  • 其中“可选扩展字段”可不使用,例如:反洗钱应用的应用预处理层 Schema 命名为: t_app_aml,相应视图 Schema 为v_app_aml。

申请规范

  • 共享元数据集群架构下,申请schema必须填写所属应用、用途描述。

资源队列申请规范

资源队列用于管理用户的查询优先级、内存利用与并发控制,避免集群压力过大,造成数据库不稳定。单个集群中所使用的资源队列控制在15个以内,所有资源队列并发之和需控制在80以内。

命名规范

  • 涉及高优作业加工的应用,应设置高优加工作业队列(高优资源队列可扩展字段_h);
  • 命名规范: resq_{数据区名称}_{应用名}_{权限组名称}_{可扩展字段},例如:实验区反洗钱应用的高优加工资源队列命名为:resq_lds_fxq_etl_h。

申请规范

  • 单个计算集群资源队列并发总数不允许超过80
  • 128节点规模以下计算集群,max_cost(I/O扫描次数)不允许超过40亿,128节点规模以上的计算集群,max_cost(I/O扫描次数)不允许超过80亿;
  • 集群中所有资源队列memory_limit(内存使用限制),不允许超过30GB。

用户组申请规范

数据库用户组用于批量的用户授权,资源队列调整等用途。

命名规范

  • 用户组命名格式: {数据区名称}_{应用名}_{权限组名称}_GRP
  • 权限组名称规范:
    • ETL(加工用户);
    • WEB(前端展现用户,默认权限SELECT);
    • QRY(查询用户,默认权限SELECT); 例如:实验区反洗钱应用的加工用户组命名为:lds_fxq_etl_grp。

用户申请规范

数据库用户用于控制数据访问权限、SQL执行时长、SQL运行并发度等限制。

命名规范

  • 复制作业需申请复制用户执行;
  • 非复制用户命名规范:
    • 用户只允许在单个计算集群中使用;
    • 涉及高优作业加工的应用,应申请高优加工用户(高优用户可扩展字段_h),且高、低优加工用户使用不同的高、低优资源队列;
    • 用户命名格式: {数据区名称}_{应用名}_{角色}_{可扩展字段}
    • 用户角色分 3 种:
    • ETL(ETL 作业用户)
    • USR( 日常运行维护用户)
    • QRY(应用查询用户),可扩展字段由应用设计确定。 例如:贴源base加工应用的 ETL 用户命名为:base_sor_etl_h
  • 复制用户命名规范:
    • 低优复制用户:系统名_目标数据库名_copy(小于20位)
    • 高优复制用户:系统名_目标数据库名_copy_h(小于20位) 例如:对私客户关系管理高优复制用户命名为:p9crm_ncr_copy_h”

申请规范

  • 一个数据库用户仅允许在一套计算集群运行作业;
  • 单个用户最大连接数不超过100,一套计算集群所有用户连接总数不超过400;
  • 申请用户时需配置SQL最长执行时间,即用户超时时间,跑批类用户默认不超过2小时,即席查询默认最大不超过12小时;
  • 固定权限类授权,需指定用户所属用户组,通过用户组进行权限管理;
  • 申请用户时需指定用户所属资源队列,禁止使用数据库默认资源队列;
  • 申请用户时,若此用户需建表(包括临时表)、插入数据,需指定用户默认表空间。

非全局对象设计规范

表、视图、序列、函数等对象由应用自行创建并维护,本章介绍在设计此类非全局对象时,应用所需遵循规范。

表设计规范

命名规范

原则上表/视图名称长度不超过30个字符,外部表不超过34个字符,为后期接口扩充预留。

  • 物理临时表命名以"TMP_“开头;
  • 备份表命名以“_bak_${日期}”结束。

数据类型

数据类型的定义与相关数据的加载和使用紧密相关,数据类型的定义决定了数据所占用的空间大小,因此,必须慎重设计数据表的字段类型。数据仓库的数据来自于多个异构的业务应用系统,通常情况下,业务应用系统的字段类型选择较为随意,不同的业务系统数据类型定义存在多样化,彼此之间差异较大;因此,在数据仓库中,需在参考源系统字段类型定义的情况下,结合数据仓库平台的特点和要求,对字段数据类型进行设计。

  • 数据类型定义需遵循以下原则:
  • 在满足业务需求的条件下,尽可能选择空间占用最小的数据类型,以节省数据存储空间;
  • CHARVARCHAR和TEXT之间不存在性能差异,在其他的DB系统中,可能CHAR会表现出最好的性能,但HashData数据库中是不存在这种性能优势的。在多数情况下,应该选择使用VARCHAR而不是CHAR;
  • 定长字符串类型选择使用VARCHAR而不是CHAR;
  • 对于Numeric类型来说,应该尽量选择更小的数据类型来适应数据;比如,选择BIGINT类型来存SMALLINT类型范围内的数值,会造成空间的大量浪费。
  • 关联表的关联字段,必须使用相同的数据类型。如果做Join的Column具有相同的数据类型(比如主PrimaryKey与外键ForeignKey),其工作效率会更高。
  • 数据仓库在处理代码转换时,如遇到例外取值,采用的方式为在前面拼一个特殊字符将其保留,以便续知道这个例外取值时可将其恢复。
  • 了尽可能的保持数据仓库类型的一致性和规范性,以及为了在数据迁移时,降低数据转换的复杂性,数据仓库中的数据类型定义不宜过于复杂,数据仓库中的常用字段类型规范如下表所示。一般情况下,应尽量使用规范的数据类型,避免出现诸如Address,INET,ARRAY等特殊类型字段。
    序号
    数据类型 选择该数据类型的字段
    1 VARCHAR(2) 标志字段
    2 VARCHAR(4) 代码字段1档
    3 VARCHAR(6) 代码字段2档
    4 VARCHAR(8) 代码字段3档、会计科目号、利率代码
    5 VARCHAR(10) 代码字段4档
    6 VARCHAR(12) 代码字段5档
    7 VARCHAR(15) 代码字段6档
    8 VARCHAR(20) 超长代码字段
    9 VARCHAR(60) 加载任务
    10 VARCHAR(30) 交易序号、流水号、顺序号、业务序号、凭证编号、当事人编号、资产 编号、事件编号、业务编号、电话号码、手机号码、传真号码、事由编号、地址编号、债券编号、证件号 码、个人姓名、以及源系统过来的各种编号字段
    11 VARCHAR(60) 协议编号、项目编号、单位名称、申请编号
    12 VARCHAR(100) 地址、项目名称、摘要
    13 VARCHAR(200) 较长的说明描述字段
    14 VARCHAR(500) 较长的说明描述字段
    15 VARCHAR(1000) 较长的说明描述字段
    16 VARCHAR(2000) 较长的说明描述字段
    17 VARCHAR(5000) 较长的说明描述字段
    18 TEXT 超大文本字段
    19 DATE 日期
    20 TIME 时间
    21 TIMESTAMP 时间标签
    22 BOOLEAN 布尔类型
    23 SMALLINT 较小的整数,-32768 – +32768
    24 INTEGER 一般大小的整数,最大约21亿
    25 BIGINT 超大整数
    26 DECIMAL(18,2) 金额、面积等
    27 DECIMAL(18,4) 评分
    28 DECIMAL(18,6) 久期、凸性
    29 DECIMAL(18,9) 汇率
    30 DECIMAL(18,10) 折算汇率
    31 DECIMAL(9,2) 比例、占比、抵押率
    32 DECIMAL(9,6) 利率、费率、税率、浮动率、久期、凸性

行列存储

HashData数据库支持两种存储模型,分别是追加优化存储 (AO Table)和列存储(CO Table),其中追加优化存储是默认存储类型。追加优化存储适用于大量数据的批量加载,从而可以获得较好的存储性能和压缩性能。追加优化存储同时支持更新和删除操作。当用户的表包含较多的列,且大部分列并不会用在查询中的时候,可以考虑使用列存储从而节省IO访问的开销。数据表在默认情况下采用行存储的方式,这种方式适用于绝大多数的使用场景。

在HashData数据库当中,应尽量使用行存储。采用列存储的方式,在某些使用场景下,能提升查询性能,采用列存储,必须满足下面几个条件:

  • 数据表不被频繁INSERT,因为列存储,每一列都独立一个存储文件,列存储对于写入操作性能较差,每条记录都需要写入到不同数据文件上;因此,列存储适合一次写入,多次读取的数据表;
  • 查询使用到的Column数量很少,列存储适合在 SELECT 中针对单列做聚合操作,或者在WHERE 中针对单列做条件过滤;例如:
    Select sum(salary) From employee_payment 
    WHERE employee_type=contract
    

综合以上考虑,HashData数据库行列存储规范如下:

  • 通常情况下采用行存储,只有在频繁查询,并且访问模式是只访问宽表少量字段的情况下,才优使用列存储;
  • 字段数量小于10的数据表,禁止使用列存储;
  • 表的记录数/(集群数据节点数)小于100万条,或者常用读取字段数大于总字段数50%,或者频进行UPDATE、DELETE操作的表,避免使用列存储;
  • 面向用户访问的表,表的所有查询SQL语句中查询的字段数低于表总字段数的50%时,若使用列存建议压缩存储;
  • 面向批处理加工的表,建议使用行压缩存储形式;
  • 采用列压缩存储的表,收集统计信息时,必须指定字段名,字段包括关联字段、分布键和常用过条件字段。

数据压缩

默认情况下,HashData数据库并不压缩用户数据。在存储数据的时候对数据进行压缩是一把双刃剑,首先压缩数据可以减少数据查询时的IO 开销,但是解压数据带来了更多的 CPU 的开销。因此只有当 IO 收益大于 CPU开销的时候,压缩存储数据才会有收益。因此仅当用户确认压缩数据可以带来查询性能提升的时候,才应当压缩存储数据。云数据支持多种压缩算法。评价一个压缩算法通常从压缩比和解压性能两方面考虑。其中压缩比越大,IO收益就会越大。解压性能越好,CPU 开销就越小。建议使用 zstd 压缩算法。表压缩的设计应遵循如下的规范:

  • 表的记录数大于10亿条,必须建成压缩表;
  • 需要频繁更新的数据表不建议使用压缩存储;
  • 压缩表建议统一使用zstd压缩算法,压缩级别为5 (appendonly=true, compresstype=zstd, compresslevel=5),此压缩设置满足大多数的使用场景;
  • 所有不再更新的历史数据表、备份表、归档表统一使用压缩存储。

分布键设置

基于HashData数据库的特点,每张数据表都必须指定分布键DK,数据库根据数据分布键(Distributed Key,简称DK)值来决定记录分布在哪一个segment上,DK不仅决定了数据在集群节点上的分布,还严重影响数据查询和处理操作的执行效率,需要非常慎重地选择数据表的分布键。对于数据库,DK的选择需要遵循以下原则:

  • 数据均匀分布原则 为了尽可能达到最好的性能,所有的实例应该尽量储存等量的数据。若数据的分布不平衡或倾斜,那些储存了较多数据的实例在处理数据时将需要耗费更多的工作量。为了实现数据的均匀分布,可按下述方式进行判断:
    • MPP库表选取字段作为分布键时,可按下述步骤进行判断:
    • 字段唯一值比例>50%,字段唯一值比例=字段唯一值数量/数据记录总数量。查询SQL如下:
      SELECT COUNT(DISTINCT ${column_name})/COUNT* FROM ${table_name};
      
    • 字段最高重复度<1,字段最高重复度=字段重复最高次数 * 集群实例数*2/表记录总数量。查询SQL如下:
      SELECT MAX(value_count)*2*(SELECT COUNT(content) FROM gp_segment_configuration WHERE content<>-1)/SUM(value_count) FROM (SELECT ${clounm_name},COUNT(*) value_count FROM ${table_name} GROUP BY a) A;
      
  • 本地操作原则 数据库在处理关联、排序、聚合等操作时,若此类操作涉及字段包括所有分布键,且不未对分布键进行数据类型转换,且关联字段顺序需与分布键顺序保持一致,可在各segment本地完成数据处理,无需进行数据重分布或广播。
  • 均衡的查询负载原则 基于集群木桶效应特性,各节点负载均匀,可有效保证集群效率。通过合理的DK设计,尽量使得查询处理的负载均匀分布在每个节点上,并且尽量保证WHERE条件产生的结果集在各个节点上也是均匀的。例如,表A分布键为A.a,避免出现以下查询:
    SELECT * FROM A WHERE A.a=xxx;
    
  • DK精简原则 DK字段不宜过多,DK字段越少,关联、排序、聚合等操作进行本地哈希概率越大。DK字段不允许超过3个。

基于以上原则,HashData数据库的数据表分布键设计规范如下:

  • 选择无需进行UPDATE操作的字段作为分布键:
  • 分布键字段原则上为1个,不允许超过3个;
  • 选择保证数据分布均匀的字段作为分布键,评估方式可参考上文数据均匀分布原则;
  • 每个数据表必须通过distribiute by子句显式指定分布键DK,不允许使用默认DK 的方式创据表;
  • 尽量避免使用随机分布策略,随机分布将导致关联等查询需进行数据重分布,影响执行性能,分布的适合使用场景:
  • 查询时无需进行关联、聚合、排序等操作;
  • 只与小表关联的数据表。
  • 为了保证数据分布均匀,在没有合适字段作为分布键的情况下,应选择数据表的主键作为分布键;
  • 选择高频出现在关联、聚合、排序查询条件中的字段作为分布键;
  • 避免关联、聚合、排序条件,对分布键字段进行函数运算;
  • 关联查询字段尽量保证包含所有分布键,且关联字段顺序尽量保证与分布键一致,保证可进行关联;
  • 中间过程表、临时表、派生表的DK应尽可能保证与后续关联、排序、聚合查询字段保持一致,保持和源表一致;

数据分区设置

表分区用于解决大表查询效率问题,比如事实表,解决办法为对表进行分区,、分成很多小且更容易管理的子分区。分区表在执行给定的查询语句时,扫描相关的部分数据,而不是全表的数据从而提高查询性能。但是,在数据库中,每个分区子表都对应一张独立的数据表,系统通过父子表之间的继承关系来维护分区定义信息。如果过多的数据表进行了分区,会造成表对象数量过多,系统元数据急剧膨胀,给系统的运行和维护带来很大负担。因此,还要综合考虑系统的表数据量情况,才可决定是否对数据表进行分区。

以下是数据分区规范:

  • 表的记录数大于10亿条或表大小超过1TB,请使用分区;
  • 全表记录数少于1亿条时避免使用分区;
  • 优先使用范围 (Range) 分区,否则使用列表 (List) 分区;
  • 单个分区记录数不能超过10亿,单个分区大小不能超过1TB;
  • 大表分区数量推荐不超过200个,最多不超过300个;
  • 禁止将分布键作为分区键;
  • 禁止使用多级分区;
  • 列存表,避免使用分区;
  • 原则上禁止创建默认分区,分区键进行范围过滤时,一定会扫面默认分区,产生不必要的IO损耗,配置默认分区,该分区大小需小于200GB;
  • 优化器关闭情况下,分区字段不允许UPDATE,需要用DELETE + INSERT 替代实现;
  • 一年以上历史数据需存入历史分区,且及时进行历史数据清理,避免历史分区过大;
  • 及时删除不需要的历史分区和空分区,预创建的分区表,周期不能超过一年;
  • 禁止在大表整改、全量数据迁移场景外,对分区大表进行全表扫描,针对分区大表查询需添加分区选条件,且避免对分区字段进行函数运算,导致全表扫描;
  • 针对分区表查询SQL 需使用使用不变操作符(例如 =,<, <=, >=, <>),保证查询优化器才会执行分区裁剪;
  • 选择性扫描可以识别查询中的 STABLE 和 IMMUTABLE 函数,但是不能识别 VOLATILE 函数。例如查询优化器对下面的 WHERE 子句: date > CURRENT_DATE 可以启用分裁剪,但是如果 WHERE 子句如: time > TIMEOFDAY, 则不会启用分区裁剪。通过检查查询的EXPLAIN 计划验证是否执行分区裁剪非常重要。

DDL 操作

DDL 操作中,一般 ALTER 语句经常需要对数据表加排它锁,导致查询语句因为封锁而等待,进而又阻塞其他操作。对标进行DDL操作时,需遵循以下规范:

  • 避开业务高峰进行ALTER、TRUNCATE、VACUUM等会导致锁表的操作;
  • 若需对大表进行分区、分布键改造,建议采用重建新表,将数据导入新表的方式进行改造,避免导致长时间锁表,其中分区表避免直接操作父表,需按子表导入数据,避免因集群节点故障等场景,导致全表需重新导入;
  • 进行大表改造后,遗留备份表应于1个月内清除;
  • 对于存有大量历史数据的分区表,避免分区表的父表上进行 VACUUM 操作和 ALTER TABLE… reorganize 操作,对分区父表进行DDL操作,消耗时间较长,建议逐个按对分区子表进行处理,避免因SQL执行超时、数据库节点故障等场景导致执行失败。

视图设计

视图的设计应遵循如下规范:

  • 视图包含的关联查询数量(包括嵌套视图的子查询)不超过15个;
  • 视图定义的字段数量不超过1600个;
  • 禁止在视图定义中使用ORDER BY
  • 排序语句,可在查询视图结果后再进行排序;
  • 视图中包含两张及以上大表的关联计算、聚合运算,计算数据量超过1TB/1亿行,视图的访问效率低,建议落地成物理表;
  • 频繁访问(单日>5次)且包含两张以上表关联的视图,建议物化成表;
  • 视图嵌套超过两层(多层嵌套子查询的效率不高)的视图,建议物化成表;
  • 只有查询表数据的权限的用户,由表的创建用户为访问用户创建视图,并授予查询用户访问该视图权限。
  • 依赖于单张表的视图,通过视图Delete或Truncate会将删除源表中的数据,应用在创建视图授权应注意权限控制,避免下游应用通过视图误删源表数据。

Sequence设计

序列常用于在新增记录时自动生成唯一标识符。

  • 在HashData数据库中,序列由Master上的进程seqserver负责产生。 在HashData数据库中,避免在大表中使用Sequence来生成唯一标识。若确实需要使用,应提前按需要量生成序列数,例如:
    create sequence seq_name cache 1000 start with 1
    

    该SQL表示创建一个名为seq_name的sequence,从1开始分配,每个segment实例从master申请序列号时都申请1000个,不是每次需要用时只申请1个;

  • 不允许在UDATE和DELETE 语句中使用序列的nextval函数;
  • 当前MPP不支持序列的currval 和astval 函数;
  • Sequence存在性能问题,不建议使用序列。
  • 创建sequence时,cache的大小和插入记录数的比例1:1000,也就是说如果一次插入10000条cache应该设置为10。

函数设计规范

  • 不允许自定义函数嵌套,单个函数体不允许超过300行;
  • 不允许用户在PUBLIC Schema下创建对象;
  • 函数体内尽量避免使用循环;
  • 不要使用函数进行复杂的数据处理操作,应使用外部脚本或程序来实现;
  • 不要在函数中进行大规模的INSERT、UPDATE、DELETE、TRUNCATE 等数据操作,函数中的所 SQL 操作都包含在一个事务当中,若处理逻辑非常复杂,耗时将较久,相关对象的锁将一直持有 致降低系统的并发性和性能;
  • 为了保证性能,函数类型应尽量使用 immutable 函数,对于不能使用 immutable 函数实 处理逻辑,应使用外部脚本实现。

临时表设计规范

  • 作业固定处理逻辑使用的临时表,创建成物理表,保留表结构。在作业执行过程中复用;
  • 对于其它数据库迁移至MPP的脚本,应将临时表物理化并重用;
  • 临时存储数据的表,若表结构后续还需使用,建议使用完成后,执行TRUNCATE 清理数据,否则应DROP表;
  • 尽量避免频繁的建表、删除表操作,避免导致系统元数据表的膨胀,系统性能下降;

数据库访问规范

数据库配置访问控制文件:pg_hba.conf,用于控制哪些用户,哪些IP可访问数据库,若pg_hba.conf未配置访问权限,将报错

“FATAL:no pg_hba.conf entry for host “XX.XX.XX.XX” user “XXX””

本章介绍MPP集群网络访问限制及规范,数据库访问控制规范。

网络访问规范

  • 数据库服务端口:5432,可在客户端主机输入:telnet 集群 Master IP 5432验证网络连通性;
  • 如果到集群网络测试未连通,需提交请求,申请开放对等连接;

数据库访问控制规范

确认客户端服务器到集群网络连通性后,需配置数据库访问控制文件(pg_hba.conf),用户才能以指定数据库用户,通过客户端IP访问数据库。

pg_hba.conf文件配置需提供5个字段,各字段配置规范如下所示:

  • 数据库访问方式:格式为字符串,支持local(本地)/hosts(远程),应用仅能申请host式;
  • 需访问数据名:格式为字符串,多个数据库用“,”分隔;
  • 需访问数据库用户名:格式为字符串,多个用户可用“,”分隔,一个用户仅能访问一套计算集群;
  • 需访问数据库IP:格式为IP/子网掩码;
  • 数据库认证方式:格式为字符串,支持trust(免密)/md5(加密认证)。

开发规范

本章节介绍各类语言数据库脚本开发规范,其中包括:SQL开发规范、存储过程开发规范、PERL脚本开发规范。

SQL开发规范

SQL代码基本要求

  • 代码行清晰、整齐、层次分明、结构性强,易于阅读;
  • 代码中应具备必要的注释以增强代码的可读性和可维护性;
  • 代码应充分考虑执行效率,保证代码的高效性。

大小写规范

  • 创建数据库对象,包括表名称、视图名称、函数名称、字段名、别名等对象时,不能使用双引号,或者对象名不能放在双引号中;
  • 所有SQL 语句中的保留字都统一采用大写,例如SELECT、FROM、WHERE、AND、OR、UNION、INSERT、DELETE、GROUP、HAVING、COUNT等等;
  • 表名、视图名、函数(FUNCTION)、字段名、字段别名等,使用规范命名,不能包含中文和特殊字符,对象名称应只包含字母、数字和“_”,不能包含其他字符。

缩进和换行规范

  • 整个SQL语句尽量按照子句进行分行编写,SELECT、FROM、WHERE、UPDATE、DELETE 等每个关键字都应另起一行;
  • 同一级别的子句间要对齐;
  • 逗号放在每行的开头;
  • 分号放在SQL语句的最后,单独占一行;
  • 每行宽度不超过256字符(每个字符为8个点阵宽),超过行宽的代码可折行与上行左对齐编排;
  • 每个字段后面,使用字段标题作为注释;
  • 在所有需要缩进的地方,每次缩进4格,在一下情况必须进行缩进:
    • 不同层次的SQL语句之间;
    • SELECT 、INSERT 、UPDATE 等关键字之后的字段列表和关键字之间。例如:
      SELECT
           sa_acct_no             -- 账号
          ,saacn_11               -- 记录长度
          ,saacn_db_timestamp     -- 时间戳
          ,sa_psbk_no             -- 存折册号
          ,sa_pab_d1_dt           -- 存折挂失日期
          ,sa_today_csh_rmb       -- 当日累计取现金额(人民币)
          ,sa_risk_level          -- 风险等级
      FROM
          app_fs.tapp_saacnacn_c
      WHERE
          p9_start_date = date'2011-01-01'
      

运算符前后间隔规范

算术运算符、逻辑运算符前后至少要保留一个空格。例如:

SELECT First_Name
      ,Last_Name                            
      ,Employee_Number                      AS Employee_Id
      ,Salary_Amount                        AS Employee_Salary
      ,(Salary_Amount + Salary_Amout * 2) / 1.5
FROM  Employee                             AS Employee_Salary_Double
WHERE Salary_Amount > 35000.00
AND   Salary_Amount < 85000.00
OR    Department Number = 403
ORDER BY First_Name
;

CASE语句编写规范

SELECT 语句中对字段值进行判断取值的操作将用到的CASE语句,正确的编排CASE语句的写法可加强代码行的可阅读性。CASE语句编写需遵循以下规范:

  • CASE语句从CASE开头到END结束要用括弧包括起来,并给结果值赋别名字段;
  • WHEN子语在CASE语句的下一行并缩进两个缩进量后编写;
  • 每个WHEN子语一行编写,当然如果语句较长可换行编排;
  • CASE语句必须包含ELSE子语。例如:
    SELECT  First_Name
           ,Last_Name                            
           ,Employee_Number                      AS Employee_Id
           ,Salary_Amount                        AS Employee_Salary
           ,(CASE
                 WHEN Salary_Amount < 5000.00 THEN Salary_Amount * 2
                 WHEN Salary Amount < 6000.00 THEN Salary Amount * 1.5
                 ELSE ( Salary_Amount + Salary_Amount * 2 ) / 2.5
             END
            )                                    AS Employee_Salary_ Double
    FROM   ${PDATA}.Employee
    WHERE  Salary_Amount > 35000.00
    AND    Salary Amount < 85000.00
    OR     Department_Nurber = 403
    ORDER BY First_Name
    ;
    
  • CASE WHEN语句个数不超过20个,单个CASE WHEN条件语句不允许超过10行;

SQL语句注释编写规范

  • 对于较为复杂的数据操作例程应有充分的注释,注明实现的功能,业务逻辑关系输入输出关系等 容;多行注释可用“ /* */ ”来标识,这种类型注释还可以注释在SQL语句中间,单行注释可 “—”,例如:
     /*
         For G01-2
         各项货款按照五级分类统计
     */
    
     SELECT   SUM( CAST (dkye1 AS FLOAT) * Exchange_Rate)    AS  dkye1   -- 正常类
             ,SUM( CAST (dkye2 AS FLOAT) * Exchange_Rate)    AS  dkye2   -- 关注类
             ,SUM( CAST (dkye3 AS FLOAT) * Exchange_Rate)    AS  dkye3   -- 可疑类
             ,SUM( CAST (dkye4 AS FLOAT) * Exchange_Rate)    AS  dkye4   -- 次级类
             ,SUM( CAST (dkye5 AS FLOAT) * Exchange_Rate)    AS  dkye5   -- 损失类
             ,CAST('20121130' AS DATE)                                   -- 业务日期
     FROM dwods.a_cm_gdhthz;
    
  • 如果脚本SQL语句由多条组成,则应该在每一条SQL语句前面加注释描述该SQL语句的作用。例如:
    -- 1.提取基础层中贷款数据
    -- 1.1建立临时表 vt_check_ln
    CREATE TEMPORARY TABLE vt_check_ln
    (
        Org_Cd          CHAR (9)
       ,Currency_Cd     CHAR (2)
       ,Gl_No           CHAR (8)
       ,Bal             DECIMAL (18,2)
       ,Sts             CHAR (1)
       ,Overdue_Bal     DECIMAL (18,2)
       ,Ln_Busn_Typ     CHAR (3)
    )
    WITH ( APPENDONLY=TRUE, COMPRESSTYPE=QUICKLZ, ORIENTATION=COLUMN )
    DISTRIBUTED BY ( Org_Cd, Currency_ Cd, Gl_No )
    ;
    -- 1.2提取基础层中货款数据,转换币种为DCC的币种
    INSERT INTO vt_check_ln
    (
        Org_Cd         
       ,Currency_Cd   
       ,Gl_No           
       ,Bal            
       ,Sts             
       ,Overdue_Bal     
       ,Ln_Busn_Typ    
    )
    SELECT
    ...
    ;
    

    **注意**:SQL段的注释要把操作目的写详细,不要写诸如”创建临时表”、”插入到目标表”之类表 不清楚的注释。

  • 在SELECT语句中,源表的每个字段后面使用字段标题作为注释,其他语句中,尽量对字段做注释 尤其是经过加工处理的字段,例如:
     INSERT INTO T03_FIN_ACCI_VI_NEW
     (
         Ta_Client                                           /*TA交易账号*/
         ,Ta_Code                                            /*TA代码*/
         ,Prd_Type                                           /*业务类别代码*/
         ,In_Client_No                                       /*理财客户编码*/
         ,Client_Manager                                     /*开户柜员编码*/
         ,Status                                             /*协议状态代码*/
         ,Open_Flag                                          /*开户方式代码*/
         ,Open_Date                                          /*开通日期*/
         ,Agt_No                                             /*理财账号*/
         ,Open_Branch                                        /*所属机构编号*/
     )
     SELECT   COALESCE(Al.Ta_Client, '')                     /*TA交易账号*/
             ,COALESCE(A1.Ta_Code, '')                       /*TA代码*/
             ,COALESCE(A1.Prd_Type, '')                      /*业务类别*/
             ,COALESCE(Al.In_Client_No, '')                  /*内部客户编号*/
             ,COALESCE(A1.Client)Manager, '')                /*客户经理*/
             ,COALESCE(A1.Status, '')                        /*账户状态*/
             ,COALESCE(A1.Open_Flag, '')                     /*开户方式*/
             ,COALESCE(Al.Open_Date, 0)                      /*开通日期*/
             ,COALESCE(Al.Asset_Acc, '')                     /*理财账号*/
             ,COALESCE(A1.Open_Branch, '')                   /*理财账户所属机构*/
     FROM    ${SDSDATADB}.S05_TBASSETACC${SHORT_DATE} A1
     ;
    

WHERE条件编写规范

  • 每个过滤条件单独一行;
  • AND OR 等关键字放行首。例如:
    SELECT 
        ,t1.LN_LN_ACCI_NO               -- 贷款账号
        ,t1.LNLNS_DB_TIMESTAMP          -- (空值)
        ,t1.LN_FINL_VRSN                -- 账务版次
        ,tl.LN_DB_MNTN_NO               -- 主档维护版次
        ,t1.LN_CUST_NO                  -- 客户编号
        ,t1.LN_CRLMT_NO                 -- 贷款额度编号
        ,tl.LN_OD_LN_BUSH               -- 透支之放款业务
    FROM
        BASEV_FS.VODDC_LNLNSLNS_SH_T1
    WHERE
        T1.LN_BUSN_TYP = REPLACE(SUBSIR(T2.PRODUCT_SUBSECTION_ID,6,4),'-','')
        AND SUBSTR(T2.PRODUCT_SUBSECTION_ID,5,1)='D'
        AND T2.P9_DEL_FLAG=0
    
  • 在WHERE条件过滤中,应将函数处理放在等式的右边,以提高查询性能,禁止对关联、过滤字段进行函数转换,导致无法本地哈希或进行分区筛选;
  • 针对分区表的访问,需带上分区字段的筛选条件,针对拉链表的访问,需带上开闭链条件的筛选

元数据查询规范

  • HashData数据库采用共享元数据架构,禁止对元数据进行全表扫描,若应用用户SQL对元数据集群进行全表扫描,将发送报错“Sequence scan on catalog is disabled”

  • 查询元数据需指定筛选条件,使用元数据索引,常用系统表索引如下所示:

    系统表名 索引字段
    pg_namespace oid
    pg_namespace nspname
    pg_class oid
    pg_class relname, relnamespace
    pg_attribute attrelid, attname
    pg_attribute attrelid, attnum

    例如,查询pg_class可通过relname作为筛选字段;

    select * from pg_calatlog.pg_class WHERE relname=tablename::name;
    

SQL的Slice上限

为了提高查询执行并行度和效率,优化器把一个完整的分布式查询计划从下到上分成多个Slice,每个Slice负责计划的一部分。一般情况下,SQL越复杂,关联的表越多,所产生的Slice越多。

每个Slice都会消耗一定的内存资源,如果一个SQL的Slice非常多,就会消耗大量的内存资源,可能导致整个系统内存资源不足。因此,涉及MPP SQL查询语句,需遵循每条SQL的Slice数量不能超过50个的规范。每条SQL的Slice数量,可以通过查询执行计划获取:

通过explain命令,获取执行计划,执行计划第一行会显示这条SQL会产生多少Slice(如图红框):

表连接语句规范

  • 表连接中的每个表应指定缩写的别名;

  • 多表关联的时候,所有的关联必须写成JOIN的形式,例如:

    SELECT
       A1.sa_acct_no
      ,A1.saacn_ll
    FROM
       app_fs.tapp_saacnacn_c A1
       INNER JOIN app_fs.tapp_saacnaco_t A2 ON Al.sa_acct_no =A2.sa_acct_no
    

    而不允许写成如下形式:

    SELECT
       A1.sa_acct_no
      ,A1.saacn_ll
    FROM
       app_fs.tapp_saacnacn_c A1
      ,app_fs.tapp_saacnacn_t A2
    WHERE A1.sa_acct_no =A2.sa_acct_no
    
  • 一个SQL语句中,多表关联的关联表不能超过15张物理表,若涉及视图关联,请对查询执行explain操作,查询执行计划,保证查询关联物理表不超过15张;

  • 禁止使用产生笛卡尔积的关联形式,关联字段关联后(字段重复值的乘积)的重复值不超过100万,增加筛选,避免大量重复空值进行关联;

  • 多表做INNER JOIN时,使用小表作为驱动表,将小表放置JOIN左边;

  • 在使用小表 LEFT JOIN 超大表(记录数过亿)时,优先对小表和超大表进行INNER JOIN,再将小表对子查询结果进行LEFT JION 的方式实现。这样既可以提高性能,也能避免MPP 产生大量的临时文件;因为在HashData数据库中,对于LEFT JOIN 语句,生成执行计划时会固定使用右表的记录构造Hash表,然后用Hash Join 的方式实现关联;如果右表非常大,会导致Hash表需要占用大量的内存,如果内存超出限制,系统会把Hash表的内容,写入到文件系统的临时文件中,如果右表是一个超大表,可能在执行此语句的时候,系统会写入大量临时文件,造成系统占用空间大幅增加

    例如:如下LEFT JOIN 语句:

     -- left join 超大表
     SELECT
         A.ci_cust_no
        ,A.p9_split_branch_cd
        ,B.ci_cust_по
     FROM base_fs.aoddc_ciccrcc0_h AS A
         LEFT JOIN base_fs.aoddc_cicifci0_h AS B
         ON A.ci_cust_no=B.ci_cust_no
         AND A.p9_split_branch_cd =B.p9_split_branch_cd
    

    其执行计划如下:

    从执行计划可以看出,系统会扫描右表 aoddc_cicifci0_h,对其所有数据建立一个Hash表,如果aoddc_cicifci0_h 是一个超大表,那么LEFT JOIN 可以改写如下:

     -- 改写为先 INNER JOIN 再 LEFT JOIN
     WITH TEMP_INNER_RESULT AS (
     SELECT
         B.ci_cust_no
        ,B.p9_split_branch_cd
     FROM base_fs.aoddc_ciccrcc0_h AS A
         INNER JOIN base_fs.aoddc_cicifci0_h AS B
         ON A.ci_cust_no=B.ci_cust_no
         AND A.p9_split_branch_cd =B.p9_split_branch_cd
     )
     select
         A.ci_cust_no
        ,A.p9_split_branch_cd
        ,B.ci_cust_no
     from base fs.aoddc_ciccrcc0_h AS A
         LEFT JOIN TEMP_INNER_RESULI AS B
         ON A.ci_cust_no=B.ci_cust_no
         AND A.p9_split_branch_cd =B.p9_split_branch_cd
    
  • 同样,在使用超大表RIGHT JOIN 小表的时,优先将小表与超大表INNER JOIN,再将子查询结果与小表进行RIGHT JOIN 的方式实现;

  • 关联字段尽量包含所有分布键,且关联字段避免做函数处理,否则会导致数据重分布,示例如下:

    --错误的关联方式,导致数据重分布
    Select * FROM base_fs.aoddc_ciccrcc0_h AS A 
    LEFT JOIN temp_result AS B ON trim(A.ci_cust_no)=B.ci_cust_no</p>
    --正确的关联方式
     Select * FROM base_fs.aoddc_ciccrcc0_h AS A 
    LEFT JOIN temp_result AS B ON A.ci_cust_no=B.ci_cust_no
    

排序语句规范

  • 禁止在视图定义中使用ORDER BY 排序语句,可对查询结果进行排序;
  • ORDER BY 语句执行成本很高,建议尽量避免使用;
  • 避免在大的数据集上执行排序操作;
  • 禁止使用UNION语句,内部实现需要对数据排序,建议使用UNION ALL及GROUP BY实现;
    Select cust_no,cust_name FROM BigTableA 
    Union
    Select cust_no,cust_name FROM BigTableB
    --改为UNION ALL 和 group by 实现
    Select cust_no,cust_name FROM
    (
    Select cust_no,cust_name FROM BigTableA
    Union ALL
    Select cust_no,cust_name FROM BigTableB
    ) AS P
    Group by cust_no,cust_name
    
  • 数据去重尽量使用group by,不要使用distinct;
  • 数据去重避免使用partition by,需对数据排序,使用group by语句,例如:
    SELECT * FROM table a INNER JOIN 
    ( SELECT pk1,pk2,min(ctid) minctid
    FROM table 
    GROUP BY 1,2) AS b
    ON a.pk1=b.pk1 and a.pk2=b.pk2 and a.ctid=b.minctid</p>
    --(关联字段应包含分布键)
    

嵌套子查询语句规范

  • 关联子查询(包括WITH语句)数量不要超过5个,建议将中间结果集落地为物理表,分为多个较简单的执行语句实现;
  • 子查询嵌套的层次不要超过3层;如果查询过于复杂,应对查询进行拆分,将中间结果集落地为物理表,分为多个较简单的执行语句来实现;
  • 避免与复杂的子查询进行关联,应将子查询提前物化成物理表;
  • 避免使用使用子查询A LEFT JOIN子查询B此类语句。

IN语句使用规范

避免NOT IN语句,使用LEFT JOIN的方式实现,并且尽量使用分布键作为关联条件。

例如:

--NOT IN语句
SELECT count(*) FROM base_fs.uoddc_saacntxn_a_test_tmp 
WHERE (sa_acct_no,sa_ddp_acct_no_det_n) NOT IN
(SELECT sa_acct_no,sa_ddp_acct_no_det_n
FROM base_fs.uoddc_saacntxn_a_test)

其执行计划如下:

从执行计划可以看出,IN语句需对字段进行去重,导致广播操作,执行成本很高,可修改为使用LEFT JOIN 形式进行优化,如下:

SELECT count(*) 
FROM base_fs.uoddc_saacntxn_a_test_tmp AS A
LEFT JOIN base_fs.uoddc_saacntxn_a_test AS B
ON A. sa_acct_no=B. sa_acct_no AND A.sa_ddp_acct_no_det_n =B. sa_ddp_acct_no_det_n
WHERE B.sa_acct_no IS NULL

其执行计划如下:

后面一种实现方式,性能比NOT IN 的方式改善很多。

统计信息收集规范

HashData数据库SQL执行依赖于统计信息是否准确,若统计信息未收集,可能引起大表广播、大表nestloop等大量消耗资源的操作,因此应用在执行INSERT、DETETE、UPDATE等操作后,应及时收集统计信息,避免因统计信息不准,引起数据库效率问题。

  • 以下场景建议收集用户表统计信息:
    • 使用 copy、 gpfdist 等方式进行大数据量加载之后;
    • 在大数据量的 INSERT、 update、 DELETE 操作(数据变化量超过 500万,或超过原表 30%)之后;
    • 对表进行reorganize后,需执行ANANLYZE操作,以收集统计信息;
    • 对使用create table xxx as (SELECT …) with no data 方式创建的表,插入数据后必须手工收集表的统计信息。
  • 系统表由DBA统一维护,禁止对收集系统表统计信息;
  • 插入大量数据前,建议关闭gp_autostate_mode (on_no_stats=>none),数据插入后,执行ANANLYZE 收集统计信息, 例如:
     -- 关闭自动统计信息收集
     set GP_AUTOSTATS_MODE=NONE;
     -- 插入大量数据
     insert into tablexxxxx
     select * from ext_tablexxxxx;
     -- 收集统计信息
     Analyze tablexxxxxx;
    
  • 对于分区表,如果只在部分分区更新、插入、删除了数据,避免对父表执行统计信息收集,应该指定子分区进行 ANANLYZE;
  • 对于宽表(字段数超过 30),如果只 update 部分列,建议只针对变化的列收集统计信息:
    ANANLYZE table(column1,column2,);
    
  • 若大表数据频繁更新,收集统计信息时,ANANLYZE时指定需要收集统计信息的列,通常只需要收集分区键、分布键、关联条件字段、排序、聚合、WHERE条件使用字段。
     -- 收集表的所有字段统计信息,不推荐
     Analyze bigtable;
    
     -- 收集常用查询、关联字段统计信息,推荐
     Analyze bigtable(ID,create_date);
    

VCUUM操作规范

当数据表频繁被执行DELETE、UPDATE操作后,将产生严重表膨胀,影响数据访问效率,应用需定期对表进行reorganize,解决膨胀问题。

  • 禁止执行VACCUM FULL操作,可通过reorganize后ANANLYZE达到VACUUM FULL效果;
  • UPDATE、DELETE数据量超管500万行或全表数据量30%后,需对表进行reorganize;
  • 禁止在业务高峰执行大表reorganize操作,对表进行reorganize操作将锁表,导致表数据不可访问;
  • 禁止对分区大表父表进行reorganize操作,需逐个对子分区执行reorganize;
  • 系统表维护由DBA统一进行,禁止应用对系统表执行VACUUM操作。

常见SQL优化案例

  • 善用分布键 在关联字段中,尽量包含分布键作为关联条件,避免数据重分布或广播。在SQL语句的执行计划中,应通过优化执行语句,尽量避免数据重分布操作,可使用 Explain 命令检查SQL语句是否存在redistributed,broadcast等操作,并检查操作是否合理;
    例如:两张表base_fs.aoddc_ciccrcc0_h 和base_fs.aoddc_cicifci0_h,它们的分布键一致,定义如下:

     DISTRIBUTED BY (ci_cust_no, p9_split_branch_cd);
    

    SQL语句1写法如下:

     --SQL 1,关联字段没有使用包含分布键
     SELECT count (*)
     FROM base_fs.aoddc_ciccrcc0_h AS A
         INNER JOIN base_fs.aoddc_cicifci0_h AS B ON A.ci_cust_no=B.ci_cust_no
    

    其执行计划如下:

    可见,在执行计划中,包含了重分布操作,需要在节点之间重分布数据;可将SQL语句优化,改写如下,把分布键包含进关联字段,可比较数据重分布,改善性能:

     --SQL 2,关联字段包含全都分布键
     SELECT count (* )
     FROM base_fs.aoddc_ciccrcc0_h AS A
         INNER JOIN base_fs.aoddc_cicifci0_h AS B
           ON A.ci_cust_no=B.ci_cust_no AND A.p9_split_branch_cd =B.p9_split_branch_cd
    

    其执行计划如下:

  • 避免使用UNION操作

    对于大表的UNION操作,如果不需要去重,请用UNION ALL替代,如果需要去重,请用UNION ALL及GROUP BY 替代。例如,如下语句:

    可替换为:

    从执行计划的差异上,可看出,UNION ALL 具有更好的性能,所以,如果不需要去重,仅仅是合并数据集,应使用UNION ALL。对于大表的UNION操作,如果需要去重,请用UNION ALL 加上GROUP BY替代,因为UNION 操作需要执行SORT操作,执行成本更高。去重案例如下:

    可改写如下:

  • 判断记录是否存在,应使用 LIMIT 1 子句的方式,不要使用SELECT COUNT(*) 语句。

    --判断某记录是否存在
    SELECT COUNT(*)
    FROM base_fs.aoddc_cicifci0_h
    WHERE p9_split_branch_cd='001'
    --应修改为
    SELECI 1
    FROM base_fs.aoddc_cicifci0_h
    WHERE p9_split_branch cd='001'
    LIMIT 1;
    
  • 清空数据表,应使用TRUNCATE 操作,不要使用无条件的DELETE 操作,避免VACUUM处理。 例如:

    DELETE FROM Tablexxxx ;
    -- 应修改为:
    TRUNCATE TABLE Tablexxxx;
    

存储函数开发规范

编码规范

函数中的代码编写应遵循以下规则:

  • 代码行清晰、整齐、层次分明、结构性强,易于阅读;
  • 代码中应具备必要的注释以增强代码的可读性和可维护性;
  • 代码应充分考虑执行效率,保证代码的高效性;
  • 函数尽量采用Immutable类型,避免Volatile类型,对于后者,应尽量避免频繁调用
  • 函数应尽量统一使用语言 plpgSQL 开发,只有使用plpgSQL无法实现所需功能时,才允许使用其它开发语言;
  • 尽量不使用C语言开发函数,避免因为代码缺陷或性能问题,影响数据库的稳定运行;
  • 每个函数,必须在代码头部通过规范注释,说明函数的创建者、函数功能描述、函数参数描述、创建时间、函数修改记录、修改人、修改时间等信息;例如:
     CREATE OR REPLACE FUNCIION app_fs.sf_tapp_acct02s_m(
         p_in_date_from character varying,
         p_in_date_to character varying,
         p_in_load_mode integer
     ) RETURNS void AS
     $BODY$
     /*------------------------------------------------
         #创建时间: 2013-05-07
         #创建人:   xxxxx
         #功能描述: CLPM最新企业货款债项信息,从P9数据平台贴源数据区最终目标表TODCL_LOANS_HMC获取最新全量企业货款债项数据,本程宇每月跑,将计算结果插入目标表TAPP_ACCTO2S。
         #参数说明:
         p_in_date_from: 开始日期
         p_in_date_to:   截止日期
         p_in_load_mode: 加载模式
         #修改时间:
         #修改内容:
         #修改人:
    
  • 函数本地变量全部使用“v_”开头标识,并且使用小写命名;
  • 每个变量后面,使用注释进行说明:
    --变量定义
     DECLARE
         V_DATE_FROM         DATE;                           -- 本次处理的开始数据日期
         V_DATE_TO           DATE;                           -- 本次处理的截止数据日期
         V_SP_NAME           VARCHAR(30);                    -- SP名称
         V_TAB_LEVEL         VARCHAR(20);                    -- 表所在模型层次
         V_LOG_STEP_NO       VARCHAR(20);                    -- LOG步骤编号
         V_LOG_BEGIN_TIME    TIMESTAMP := clock_timestamp(); -- LOG开始时间
         V_LOG_END_TIME      TIMESIAMP;                      -- LOG结束时间
         V_LOG_DESC          TEXT;                           -- LOG信息描述
         V_LOG_ROWCOUNT      INTEGER:=0;                     -- 影呴行数
         V_ELAPSED           INTERVAL;                       -- 单步时间
         V_ALL_ELAPSED       INTERVAL;                       -- 一共时间
         V_OUT_SOLCODE       VARCHAR(20);                    -- 错误代码
         V_OUT_ERRMSG        VARCHAR(500);                   -- 错误信息
         V_SP_BEGIN_DATE     TINESTAME := clock timestamp(); -- 过程开始时间
         V_STEP_DESC         VARCHAR(500);                   -- 描述信息
     BEGIN
         -- 关闭白动统计信息收集
         set GP_AUTOSTATS_MODE=NONE;  
    
  • 函数的代码启始和终止统一使用$BODY$ 作为标识符;
  • 函数中的SQL语句需遵循SQL开发规范中的相关规范;
  • 函数中应使用RAISE NOTICE
  • 语句输出函数执行信息,便于在发生错误时辅助诊断错误原因;例如:
    CREATE FUNCIION somefunc() RETURNS integer AS $BODY$
    DECLARE
        V_QUANTITY integer := 30;  -- 数量
    BEGIN
        RAISE NOTICE 'Quantity here is %', V_QUANTIIY;  -- Prints 30
        V_QUANTITY := 50;
    
        RAISE NOTICE 'Quantity here is %', V_QUANTIIY;  -- Prints 50
    
        RETURN V_QUANTITY;
    END;
    $BODY$ LANGUAGE plpgsql;
    
    IF oid1 IS NULL THEN
        RAISE EXCEPTION 'not exist %',sname||'.'||tname;
    ELSE
        RAISE EXCEPIION 'not exist %',sname||'.'||tname;
    END IF;
    
    • 每个函数,都有函数头说明,说明函数实现功能和参数意义

大小写规范

  • 函数名称、参数名称统一采用小写命名,使用规范命名,不能包含中文和特殊字符,对象名称应只包含字母、数字和“_”,不能包含其他字符;例如:
  • 函数本地变量全部使用“v_”开头标识,并且使用小写命名; 例如:
    --变量定义
     DECLARE
         V_DATE_FROM         DATE;                           -- 本次处理的开始数据日期
         V_DATE_TO           DATE;                           -- 本次处理的截止数据日期
         V_SP_NAME           VARCHAR(30);                    -- SP名称
         V_TAB_LEVEL         VARCHAR(20);                    -- 表所在模型层次
         V_LOG_STEP_NO       VARCHAR(20);                    -- LOG步骤编号
         V_LOG_BEGIN_TIME    TIMESTAMP := clock_timestamp(); -- LOG开始时间
         V_LOG_END_TIME      TIMESIAMP;                      -- LOG结束时间
         V_LOG_DESC          TEXT;                           -- LOG信息描述
         V_LOG_ROWCOUNT      INTEGER:=0;                     -- 影呴行数
         V_ELAPSED           INTERVAL;                       -- 单步时间
         V_ALL_ELAPSED       INTERVAL;                       -- 一共时间
         V_OUT_SOLCODE       VARCHAR(20);                    -- 错误代码
         V_OUT_ERRMSG        VARCHAR(500);                   -- 错误信息
         V_SP_BEGIN_DATE     TINESTAME := clock timestamp(); -- 过程开始时间
         V_STEP_DESC         VARCHAR(500);                   -- 描述信息
     BEGIN
         -- 关闭白动统计信息收集
         set GP_AUTOSTATS_MODE=NONE;  
    
  • 函数的保留字、关键字全部使用大写书写,例如DECLARE、BEGIN、END、IF、THEN、 ELSE、END IF、FOR LOOP 等等;

缩进与换行规范

  • 同一级别的语句要对齐;
  • 同一个代码块的DECLARE、BEGIN、END 要对齐,例如:
    CREATE FUNCIION somefunc() RETURNS integer AS $BODY$
    DECLARE
        V_QUANTITY integer := 30;  -- 数量
    BEGIN
        RAISE NOTICE 'Quantity here is %', V_QUANTIIY;  -- Prints 30
        V_QUANTITY := 50;
    
        RAISE NOTICE 'Quantity here is %', V_QUANTIIY;  -- Prints 50
    
        RETURN V_QUANTITY;
    END;
    $BODY$ LANGUAGE plpgsql;
    
  • 每行宽度不超过256字符(每个字符为8个点阵宽),超过行宽的代码可折行与上行左对齐编排;
  • DECLARE 、BEGIN、END 等关键字单独占一行;
  • 每个字段后面,使用字段标题作为注释;
    SELECT  T2.CM_RPT_MANAGE_BRH             -- 当前营业单位代码上级营业代码
           ,T1.GL_OPUN_COD                   -- 营业单位代码
           ,T1.P9_SPLIT_BRANCH_CD            -- 一级分行号
           ,T1.GL_ACCT_TYP                   -- 帐别
           ,T1.GL_LG_NO                      -- 科目
           ,T1.P9_DATA_DATE                  -- 业务日期
           ,T1.GL_DR_PRVS_DAY_BAL            -- 借方发生额
           ,T1.GL_CR_PRVS_DAY_BAL            -- 贷方发生额
           ,T1.GL_DR_AMT                     -- 借方余额
           ,T1.GL_CR_AMT                     -- 贷方余额
     FROM  BASEV_FS.VODDC_GLGLGYED_W t1,
           TMP_FS.TODDC_CMBCTBCT_SH_TEMP t2
     WHERE T1.GL_OPUN_COD = T2.CM_OPUN_COD
    
  • 在所有需要缩进的地方,每次缩进4格,在以下情况必须进行缩进:
    • DECLARE、BEGIN 、SELECT、FROM 、WHERE 等关键字之后的代码;
    • IF、THEN、ELSE 等关键字之后,应另起一行,并缩进;
    • FOR LOOP 等关键字之后;
      例如:
      IF oid1 IS NULL THEN
          RAISE EXCEPTION 'not exist %',sname||'.'||tname;
      ELSE
          RAISE EXCEPIION 'not exist %',sname||'.'||tname;
      END IF;
      
      FOR mviews IN execute sqlstr LOOP
          IF index=0 THEN
              columnstr :=columnstr||'  "'||mviews.attname||E'" '||mviews.type;
          ELSE
              columnstr :=columnstr||E',\n  "'||mviews.attname||E'" '||mviews.type;
          END IF;
          index:=index+1;
      END LOOP;
      

事务管理规范

默认情况下,在函数中所有数据操作 INSERT,UPDATE、DELETE、TRUNCATE 等等都包含在一个事务当中,如果函数执行出错,所有操作将会回滚;

函数中避免显式的 Lock 某张公共数据表,函数中的锁会一直持有到函数执行结束,在此期间,其他用户将访问该表SQL被锁,将影响集群整体执行效率;

PERL脚本开发规范

编码规范

Perl脚本代码应遵循以下规则:

  • 代码行清晰、整齐、层次分明、结构性强,易于阅读;
  • 代码中应具备必要的注释以增强代码的可读性和可维护性;
  • 代码应充分考虑执行效率,保证代码的高效性;
  • 统一使用use strict; 语句,对代码进行严格的语法检查;
  • 不要随意定义全局变量,优先使用局部变量;
  • 尽量使用标准库函数和公共函数;
  • PERL 脚本统一使用UTF8编码;
  • PERL 脚本优先使用 PSQL 的方式操作HashData数据库数据,尽量少用DBI方式;
  • 在PERL代码中,用 PSQL 连接HashData数据库时,必须通过 $ENV{‘PGPASSWORD’} 设置访问数据库的密码,不允许用无密码方式访问数据库。

PERl注释规范

  • PERL 脚本的编写建议统一使用UltraEdit,该软件自带SQL语句着色,便于脚本的编写和阅读;
  • 脚本文件开头应通过注释,说明脚本任务的名称、脚本功能、文件名称、作者、创建时间等等信息,如下图:
    #*******************************************************************************
    # BTEQ script in Perl, generate by Script Wizard
    # 任 务 名: F1151
    # 目 标 表:   
    #          F1151(参与人之间的关系)
    # 源 表 名:
    #          TBCCPSR0 组织和关联人关系
    #          TBCCPSI0 组织关联人接口信息
    #          TBCCCUS0 客户
    # 加载策略: [00](注,00:其他,01:覆盖,03:追加,04:拉链)
    # 运行周期: [01](注,1:天,2:星期,3:旬,4:月,5:季,6:半年,7:年,00:其他)
    # 脚本功能: 生成私人银行的账户数据,用来跟其他接口表关联过滤出私人银行的数据,并进行逐户存放。
    # 创建时间: 2013-06-04 14:58:19.0
    # 文 件 名: f11510200.pl
    # 作   者: yuanjianhua
    # 修改记录:
    #*******************************************************************************
    
    use strict; # Declare using Perl strict syntax
    use File::Basename;
    use Cwd 'abs_path';
    use Time::Local;
    
    require($ENV{"HOME"}."/bin/etl_base_function.pm");
    
    #
    # If you are using other Perls pachage, declare here
    #
    
  • 每个函数,都有函数头说明,说明函数实现功能和参数意义。例如:
    ######################################################################
    ##函数名: get_ddl_info
    ##参  数: $db_access_id     数据库访问控制ID
    ##        $ddl_src          DDL信息来源
    ##        $ctl_file         控制文件
    ##        $db_type          数据库类型
    ##        $db_name          数据库名
    ##        $conn_str         数据库连接串
    ##        $db_usr           数据库用户名
    ##        $db-pwd           数据库密码
    ##        $perfixion        数据库SCHEMA
    ##        $src_name         源系统编码
    ##        $src_table        源表名
    ##        $td_data_mode     TD数据字符集
    ##        $biz_dt           业务日期
    ##        $data_org         机构
    ##        $batch_no         批次号
    ##        $load_type        加载类型
    ##        $cp_db_access_id  数据复制目标DB_ACCESS_ID
    ##        $cp_src_table     数据复制目标表
    ##        $cp_src_filt      数据入职目标表过滤条件
    ##        $data_src_pre     源系统前缀
    ##        $cp_set_def_val   数据复制TD是否设置默认值
    ##        $cp_is_view       源表是否为视图
    ##        $cp_view_key      视图分布键、主键    
    ##功  能: 读取DDL信息,生成建表信息和目标表表名
    ##返回值: $tar_table        目标表
    ##        $table_cols_list  源表字段列表
    ##        $col_list_def_val 加载字段(主键设置默认值)
    ##        $cols             源表字段列表(配置文件用)
    ##        $create_sql_table 源表建表语句
    ##        $src_row          源表记录数
    ##        $gp_analyze_txt   gp设置语句
    
  • 主要变量(结构、联合、类或对象)定义或引用时,变量名能反映其含义。
  • 处理过程的每个阶段都有相关注释说明。例如:

PERL 执行SQL脚本规范

  • 在PERL脚本中,优先使用PSQL的方式执行SQL脚本,尽量避免使用DBI方式;
  • 在PSQL 代码脚本中,要求设置\timing on 开关,以便执行日志输出命令执行时长;
  • 在PSQL 命令行中,要求设置 \set ON_ERROR_STOP on ,以便 SQL 语句出错时,停止执行;
  • 在PERL脚本中,执行SQL脚本,请参考以下模板编写处理函数:
    -- 连接数据库执行SQL脚本
    sub run_pSQL_command 
    {
       $ENV{PGPASSWORD}="password"
       my $rc = open(PSQL, "| <strong>pSQL –h localhost –d sordb –U gpadmin</strong> ");
       unless ($rc){
           print "Cound not invoke PSQL command\n";
           return -1;
       }
    -- 开始执行SQL脚本 ###
    print PSQL "\\timing on\n";
    print PSQL "\\encoding UTF8\n";
    print PSQL "\\set ON_ERROR_STOP on\n";
    print PSQL&lt;&lt;ENDOFINPUT;
       
    /* 在这里输入SQL脚本进行数据处理 */
    INSERT into table_1 values (15060065653);
    INSERT into table_1 values (1506006565a);
    INSERT into table_1 values (15060065654);
    ........
    ENDOFINPUT
       
    -- 结束执行SQL 脚本 
    close(PSQL);
    my $RET_CODE = $? &gt;&gt; 8;
    -- if the return code is no zero, that means something error happen
    -- so we return 1, otherwise, we return 0 means ok
    if ( $RET_CODE != 0 ) {
            return -1;
        }
        else {
            return 0;}
        }
        --主程序
    sub main
    {
        my $ret; #config the env
        -- Call pSQL command to load data
        $ret = run_pSQL_command();
        print "run_pSQL_command() = $ret \n";
        return $ret;
        }
    

事务使用规范

对目标表进行修改(DELETE、UPDATE、INSERT、trunctate、DROP、alter等)时,将该目标表修改的所有相关的修改SQL在一个事务中,以支持SQL异常重跑。

PERL脚本返回规范

PERL 脚本返回0表示执行成功,返回非0表示执行失败;

PSQL 执行结果返回说明:

  • 执行成功;
  • PSQL程序出错,例如内存不足、文件找不到等等;
  • 连接数据库错误
  • 在设置了ON_ERROR_STOP 的方式下,执行的SQL脚本出错;

变量引用

在PERL脚本中的SQL语句中引用变量时,必须在变量名两端加花括号。例如:

SELECT
       COALESCE (A1.Ta_Client, '')     /* TA交易账号*/
      ,COALESCE (A1.Ta_Code, '')       /*TA代码*/
      ,COALESCE (A1.Prd_Type, '')      /*业务类型*/
      ,COALESCE (A1.In_Client_No,'')   /*内部客户编号*/
      ,COALESCE (A1.Client_Manager,'') /*客户经理*/
      ,COALESCE (A1.Status,'')         /*账户状态*/
      ,COALESCE (A1.Open_Flag,'')      /*开户方式*/
      ,COALESCE (A1.Open_Date, 0)      /*开通日期*/
      ,COALESCE (A1.Asset_Acc,'')      /*理财账号*/
      ,COALESCE (A1.Open_Branch,'')    /*理财账户所属机构*/
FROM  ${SDSDATADB].S05_TBASSETACC$(SHORT_DATE] A1
;

大小写规范

  • 文件句柄全部采用大写;例如:
    ##########################################################################
    # BTEQ function
    sub run_bteq_command
    {
        my $rc = open(BTEQ, "| bteq");
    
        # To see if bteq command inboke ok?
        unless ($rc) {
            print "Could not invoke BTEQ command\n";
            return -1;
        }
    
        ### Below are BTEQ scripts ###
        print BTEQ <<ENDOFINPUT>>
    
  • 静态变量和全局变量全部采用大写;
    ########################################################################################
    # Variable Section
    my $AUTO_HOME = $ENV {"AUTO_HOME"};
    
    my $DWPDATA       = $ENV{"AUTO_DWPDATA"};       #LDM
    my $DWALMMART     = $ENV{"AUTO_DWALMMART"};     #ALM
    my $DWPMART       = $ENV{"AUTO_DWPMART"};       #监管报表
    my $DWSDATA       = $ENV{"AUTO_DWSDATA"};       #SDATA
    my $DNTEMP        = $ENV{"AUTO_DWTEMP"};        #TEMP
    My $DWLOG         = $ENV{"AUTO_DWLOG"};         #LOG
    My $DWPDDL        = $ENV{"AUTO_DWPDDL"};        #PDDL
    my $DWLDDL        = $ENV{"AUTO_DWLDDL"};        #LDDL
    my $DWSDDL        = $ENV{"AUTO_DWSDDL"};        #SDDL
    my $DWBVIEW       = $ENV{"AUTO_DWBVIEW"};       #DWBVIEW
    my $DWSDATAPBSC   = $ENV{"AUTO_DWSDATAPBSC"};   #DWSDATAPASC
    
  • 普通局部变量采用小写;
  • 函数或子程序采用小写;
  • PERL 语言的保留字、关键字采用小写;例如:
    #############################################################
    ##函数名:clean_gpfdist
    ##参  数:无
    ##功  能:kill all gpfdist服务
    ##返回值:无
    #############################################################
    sub clean_gpfdist {
    
        my $wtproc=`ps -U $user -u $user -f |grep -i gpfdist |awk '''{if(\$3==1) print ("\%s\\n",\$0)}''' ` ;
    
        print_log($wtproc) ;
    
        my @process=`ps -U $user -u $user -f |grep -i gpfdist |awk '''{if(\$3==1) print ("\%s\\n",\$2)}''' ` ;
        print "@process";
        foreach (@process ) {
            print "[Atention][ETL_BASE-clean_gpfdist] clean gpfdist process $_\n" ;
            qx{kill -9 $_ } ;
        }
    }
    

缩进与换行规范

  • 同一级别的语句要对齐;例如:

     #############################################################
     ##函数名:clean_gpfdist
     ##参  数:无
     ##功  能:kill all gpfdist服务
     ##返回值:无
     #############################################################
     sub clean_gpfdist {
    
         my $wtproc=`ps -U $user -u $user -f |grep -i gpfdist |awk '''{if(\$3==1) print ("\%s\\n",\$0)}''' ` ;
    
         print_log($wtproc) ;
    
         my @process=`ps -U $user -u $user -f |grep -i gpfdist |awk '''{if(\$3==1) print ("\%s\\n",\$2)}''' ` ;
         print "@process";
         foreach (@process ) {
             print "[Atention][ETL_BASE-clean_gpfdist] clean gpfdist process $_\n" ;
             qx{kill -9 $_ } ;
         }
     }
    
  • If, for, while 等等结构控制语句后的“{”之后的语句要换行,并且缩进4个字符;例如:

     unless ((open BACKUP_CONF,"<$backup_conffile" )) {
         showTime();print "open $backup_conffile error$!\n";
         exit(1);
     }
     my %config_params;
    
     foreach (<BACKUP_CONF>) {
         print;
         chomp;
         if(!(/^#/) && (/=/)){
             my @tmp=split /=/,$-;
             $config-params{$tmp[0]}=$tmp[1];
         }
     }
    
  • “}”需要对应级别的语句首位对其,例如:

    if ( !defined($NULLDATE) ) {
        $NULLDATE = "0001-01-01";
    }
    #my $ERRDATE = $ENV{"AUTO_ERRDATE"};
    my $ERRDATE = $ENV{"ERRDATE"};
    if ( !defined($ERRDATE) ) {
        $ERRDATE = "0001-01-01";
    }
    
  • PERL中的嵌入SQL语句书写,需按照SQL规范编写;

DBI开发规范

  • 建议尽量使用PSQL方式进行脚本开发,在特殊情况下才使用DBI方式;
  • 使用DBI接口适合用在使用次数少,返回数据量较少的场景;
  • DBI在连接时,尽量满足一次连接多次使用;
  • 开发人员使用DBI连接HashData数据库操作时,在连接使用完毕之后,必须主动关闭数据库连接,释放数据库资源;

事务管理规范

  • 对需要进行事务控制的SQL 代码块,建议使用用 BEGIN; END; 的方式操作事务,BEGIN;表示开始事务,END;表示提交事务,等价于COMMIT;例如:
    [gpadmin@mdw sql]$ cat trans_sample.sql
    BEGIN;
    select * from testaa;
    
    insert into testaa(a) values(3);
    
    update testaa set a=4 where b=3;
    END;
    
  • 那么事务中的语句,只要有错误,就会回滚,只有全部成功,事务才提交;如下图:
    [gpadmin@mdw sql]$ psql testdb -af trans_sample.sql
    BEGIN;
    BEGIN
    select * from testaa;
     a
    ---
     2
     1
    (2 rows)
    
    insert into testaa(a) values (3):
    INSERT 0 1
    update testaa set a=4 where b=3;
    psql:trans_sample.sq1:6: ERROR: column "b" does not exist
    LINE 1: update testaa set a=4 where b=3;
       
    END;
    ROLLBACK
    [gpadmin@mdw sql]$
    
  • 事务应尽快提交,以便系统释放资源;
  • 事务应遵循资源最少使用原则,包含在事务中的被操作数据对象越少越好;
  • 单个SQL语句不需要显式使用BEGIN;END;的方式使用事务;
  • 所有对目标表的修改(DELETE、UPDATE、INSERT、trunctate、DROP、alter等)操作,尽量放置在最后的语句中进行并且开启事务;

JAVA开发规范

JDBC开发规范

插入的数据库的数据在1000条记录以下才能使用JDBC方式,禁止使用JDBC的方式往HashData数据库加载大量数据;

开发人员使用JDBC或ODBC连接HashData数据库操作时,在连接使用完毕之后,必须主动关闭数据库连接,释放数据库资源。

应用开发规范

为了提高SQL的执行效率,应用端程序的开发,其SQL除了遵循开发规范之外,还需要额外注意以下问题。

  • 禁止在模板中使用嵌套子查询 应用端如果使用了模板,在模板中不要使用嵌套子查询,所有模板中的嵌套子查询,建议改写成关联查询。
  • 两表关联执行DELETE语句 对于需要两表关联的DELETE SQL,比如:
    DELETE FROM BASE.T0831_ENTP_MRTG_PAWN_H t USING
    (SELECT * FROM STAGE.ENTP_MRTG_PAWN_08310007B001A v) s 
    WHERE t.P9_END_DATE = TO_DATE('29991231', 'YYYYMMDD')
    AND s.P9_SPLIT_BRANCH_CD = t.P9_SPLIT_BRANCH_CD
    AND s.ENTP_INF_IDR = t.ENTP_INF_IDR
    

    改成:

    DELETE 
    FROM BASE.T0831_ENTP_MRTG_PAWN_H t
    WHERE t.P9_END_DATE = TO_DATE('29991231', 'YYYYMMDD')
    AND (t.P9_SPLIT_BRANCH_CD, t.ENTP_INF_IDR) in
    (SELECT P9_SPLIT_BRANCH_CD, ENTP_INF_IDR
    FROM STAGE.ENTP_MRTG_PAWN_08310007B001A)
    

    数据库的优化器可以将 in 操作转化为 SEMI JOIN,相对于 JOIN,前者在遇到有大量连接结果的时候,性能优势明显。

Window函数注意问题

使用Window函数分组后,排序字段如果不是分组字段,则每次执行该SQL的结果可能不一样,会出现相同SQL每次执行得到不同结果的情况。例如,当age字段有重复值的情况下,以下SQL可能出现两次执行结果不一样的情况:

SELECT
last_value(name) over (partition by sex order by age)
FROM dss.class;

符合SQL标准的Window函数在对分组数据进行排序时,默认会将分组内第一行到当前行做二次窗口,last_value()默认取到组内第一行和当前行之间的最大值。 如果想获得组内所有数据的最后一条记录,需要对order by增加RANG限制,修改为:

SELECT last_value(name) over (partition by sex order by age 
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),* 
FROM dss.class;

window函数的count(*)等其他操作如果有按order by做运算,也需要注意上述问题。

Window函数和聚合函数使用原则

窗口函数比常规聚合函数要慢很多,所以SQL中要尽可能的向外层推窗口函数,因为越向外,结果集越小,窗口函数的代价就会降低。

运行规范

数据库连接规范

  • 用户客户端(例如pSQL,pgAdmin,SAS等)连接到数据库执行操作,操作完成后应主动关闭数据库连接,退出应用程序,释放数据库连接资源;
  • 当用户使用cognos自助查询HashData数据库时,若报表结果存在多个分页数据,应主动退出cognos客户端或cognos 报表,避免长时间占用数据库资源;
  • 如果需要终止SQL(连接),可使用“SELECT pg_cancel_backend(procpid)”进行处理;禁止强行终止(kill -9的方式)任何postgres进程,如果有长时间执行、且无法终止的会话,建议重启数据库。

作业运行规范

数据加载规范

支持使用以下方式将外部数据入库:

  • 单行插入数据,例如:INSERT INTO tablename VALUES(…);但应避免使用单行插入的方式进行大量数据加载,频繁的小数据量插入会显著恶化数据读取的性能;
  • COPY方式将外部数据导入数据库;
  • 创建外部表方式将外部数据导入数据库,采用此方式,需保证MPP集群所有节点到外部文件存放服务器网络畅通;
  • 集群间通过复制函数将其它GP/MPP集群数据导入数据库,采用此方式,需保证源端集群所有节点和目标集群所有节点网络畅通,并开放pg_hba.conf白名单。

针对上述数据加载方式,使用规范如下:

  • 避免采用单行插入方式将数据导入数据库,采用COPY或外部表导入的方式将外部数据批量导入;
  • 流式数据加载入HashData数据库,应用需设置缓存区,进行批量入库;
  • COPY加载的数据需要经过Master节点转发,数据量超过100万行,禁止使用COPY方式加载数据,使用外部表、集群间复制等方式,通过Segment节点导入数据。

产品部署/卸载

集群创建

RESTful API

POST /default/api/v2/services/warehouse

Java SDK

createWarehouse

CommonDescribeJobResponse createWarehouse(body)

Create a database service.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreWarehouseServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreWarehouseServiceApi apiInstance = new CoreWarehouseServiceApi(defaultClient);
        CoreCreateWarehouseRequest body = new CoreCreateWarehouseRequest(); // CoreCreateWarehouseRequest | 
        try {
            CommonDescribeJobResponse result = apiInstance.createWarehouse(body);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreWarehouseServiceApi#createWarehouse");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
body CoreCreateWarehouseRequest

Return type

CommonDescribeJobResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

集群删除

RESTful API

DELETE /default/api/v2/services/{id}

Java SDK

deleteService

CommonDescribeJobResponse deleteService(id, force, external)

Destroy a given service.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        String id = "id_example"; // String | 
        Boolean force = true; // Boolean | 
        Boolean external = true; // Boolean | 
        try {
            CommonDescribeJobResponse result = apiInstance.deleteService(id, force, external);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#deleteService");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String
force Boolean [optional]
external Boolean [optional]

Return type

CommonDescribeJobResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

实例管理

集群启动

RESTful API

POST /default/api/v2/services/{id}/start

Java SDK

startService

CommonDescribeJobResponse startService(id, body)

Start a service.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        String id = "id_example"; // String | 
        CoreStartServiceRequest body = new CoreStartServiceRequest(); // CoreStartServiceRequest | 
        try {
            CommonDescribeJobResponse result = apiInstance.startService(id, body);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#startService");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String
body CoreStartServiceRequest

Return type

CommonDescribeJobResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

集群停止

RESTful API

POST /default/api/v2/services/{id}/stop

Java SDK

stopService

CommonDescribeJobResponse stopService(id, body)

Stop a service.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        String id = "id_example"; // String | 
        CoreStopServiceRequest body = new CoreStopServiceRequest(); // CoreStopServiceRequest | 
        try {
            CommonDescribeJobResponse result = apiInstance.stopService(id, body);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#stopService");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String
body CoreStopServiceRequest

Return type

CommonDescribeJobResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

集群重启

RESTful API

POST /default/api/v2/services/{id}/restart

Java SDK

restartService

CommonDescribeJobResponse restartService(id, body)

Restart a service.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        String id = "id_example"; // String | 
        Object body = null; // Object | 
        try {
            CommonDescribeJobResponse result = apiInstance.restartService(id, body);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#restartService");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String
body Object

Return type

CommonDescribeJobResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

集群扩容

RESTful API

POST /default/api/v2/services/{id}/scaleout

{
  "component": {}
}

Java SDK

Gherkin

scaleOutService

CommonDescribeJobResponse scaleOutService(id, body)

Scale out a given service.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        String id = "id_example"; // String | 
        CoreScaleOutServiceRequest body = new CoreScaleOutServiceRequest(); // CoreScaleOutServiceRequest | 
        try {
            CommonDescribeJobResponse result = apiInstance.scaleOutService(id, body);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#scaleOutService");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String
body CoreScaleOutServiceRequest

Return type

CommonDescribeJobResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

集群缩容

RESTful API

POST /default/api/v2/services/{id}/scalein

{
  "component": {}
}

Java SDK

scaleInService

CommonDescribeJobResponse scaleInService(id, body)

Scale in a given service.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        String id = "id_example"; // String | 
        CoreScaleInServiceRequest body = new CoreScaleInServiceRequest(); // CoreScaleInServiceRequest | 
        try {
            CommonDescribeJobResponse result = apiInstance.scaleInService(id, body);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#scaleInService");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String
body CoreScaleInServiceRequest

Return type

CommonDescribeJobResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

集群磁盘扩容

RESTful API

POST /default/api/v2/services/{id}/volumes/resize

{
  "target_volume_size": {}
}

Java SDK

resizeVolumes

CommonDescribeJobResponse resizeVolumes(id, body)

Adjust volume size of a given service.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        String id = "id_example"; // String | 
        CoreResizeServiceVolumesRequest body = new CoreResizeServiceVolumesRequest(); // CoreResizeServiceVolumesRequest | 
        try {
            CommonDescribeJobResponse result = apiInstance.resizeVolumes(id, body);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#resizeVolumes");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String
body CoreResizeServiceVolumesRequest

Return type

CommonDescribeJobResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

日志

查询任务日志

RESTful API

GET /default/api/v2/jobs/{id}/logs

Java SDK

getJobLog

CoreJobLogResponse getJobLog(id, offset, limit)

Fetch job log.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreJobServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreJobServiceApi apiInstance = new CoreJobServiceApi(defaultClient);
        String id = "id_example"; // String | 
        Integer offset = 56; // Integer | 
        Integer limit = 56; // Integer | 
        try {
            CoreJobLogResponse result = apiInstance.getJobLog(id, offset, limit);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreJobServiceApi#getJobLog");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String
offset Integer [optional]
limit Integer [optional]

Return type

CoreJobLogResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

运维

查询集群状态

RESTful API

GET /default/api/v2/services/{id}

Java SDK

describeService

CoreDescribeServiceResponse describeService(id)

Describe the detail of a given service.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        String id = "id_example"; // String | 
        try {
            CoreDescribeServiceResponse result = apiInstance.describeService(id);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#describeService");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String

Return type

CoreDescribeServiceResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

按条件查询集群列表

RESTful API

GET /default/api/v2/services

Java SDK

listService

CoreListServiceResponse listService(id, tenant, owner, name, vendor, zone, type, status, region, healthStatus, ip, disableAutoRecovery, recovering, startDate, endDate, destroyedStartDate, destroyedEndDate, offset, limit)

List all service.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        List<String> id = Arrays.asList(); // List<String> | 
        List<String> tenant = Arrays.asList(); // List<String> | 
        List<String> owner = Arrays.asList(); // List<String> | 
        List<String> name = Arrays.asList(); // List<String> | 
        List<String> vendor = Arrays.asList(); // List<String> | 
        List<String> zone = Arrays.asList(); // List<String> | 
        List<String> type = Arrays.asList(); // List<String> | 
        List<String> status = Arrays.asList(); // List<String> | 
        List<String> region = Arrays.asList(); // List<String> | 
        List<String> healthStatus = Arrays.asList(); // List<String> | 
        List<String> ip = Arrays.asList(); // List<String> | 
        Boolean disableAutoRecovery = true; // Boolean | 
        Boolean recovering = true; // Boolean | 
        String startDate = "startDate_example"; // String | 
        String endDate = "endDate_example"; // String | 
        String destroyedStartDate = "destroyedStartDate_example"; // String | 
        String destroyedEndDate = "destroyedEndDate_example"; // String | 
        Integer offset = 56; // Integer | 
        Integer limit = 56; // Integer | 
        try {
            CoreListServiceResponse result = apiInstance.listService(id, tenant, owner, name, vendor, zone, type, status, region, healthStatus, ip, disableAutoRecovery, recovering, startDate, endDate, destroyedStartDate, destroyedEndDate, offset, limit);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#listService");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id List<String> [optional]
tenant List<String> [optional]
owner List<String> [optional]
name List<String> [optional]
vendor List<String> [optional]
zone List<String> [optional]
type List<String> [optional]
status List<String> [optional]
region List<String> [optional]
healthStatus List<String> [optional]
ip List<String> [optional]
disableAutoRecovery Boolean [optional]
recovering Boolean [optional]
startDate String [optional]
endDate String [optional]
destroyedStartDate String [optional]
destroyedEndDate String [optional]
offset Integer [optional]
limit Integer [optional]

Return type

CoreListServiceResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

查询集群组件健康状态

RESTful API

GET /default/api/v2/services/{id}/component/health

Java SDK

listServiceComponentHealthStatus

CoreListServiceComponentHealthResponse listServiceComponentHealthStatus(id, componentType, offset, limit)

List service Component health status.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        String id = "id_example"; // String | 
        String componentType = "componentType_example"; // String | 
        Integer offset = 56; // Integer | 
        Integer limit = 56; // Integer | 
        try {
            CoreListServiceComponentHealthResponse result = apiInstance.listServiceComponentHealthStatus(id, componentType, offset, limit);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#listServiceComponentHealthStatus");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String
componentType String [optional]
offset Integer [optional]
limit Integer [optional]

Return type

CoreListServiceComponentHealthResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

查询集群故障

RESTful API

GET /default/api/v2/services/{id}/faults

Java SDK

listFaults

CoreListFaultResponse listFaults(id, startDate, endDate, offset, limit)

List all faluts which service got.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        String id = "id_example"; // String | 
        String startDate = "startDate_example"; // String | 
        String endDate = "endDate_example"; // String | 
        Integer offset = 56; // Integer | 
        Integer limit = 56; // Integer | 
        try {
            CoreListFaultResponse result = apiInstance.listFaults(id, startDate, endDate, offset, limit);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#listFaults");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String
startDate String [optional]
endDate String [optional]
offset Integer [optional]
limit Integer [optional]

Return type

CoreListFaultResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

查询集群自愈详情

RESTful API

/default/api/v2/service/recoveries/{id}

Java SDK

Gherkin

listRecoveries

CoreListRecoveryResponse listRecoveries(id, startDate, endDate, offset, limit)

List all recoveries which service got.

Example

// Import classes:
import cn.hashdata.cloudmgr.sdk.ApiClient;
import cn.hashdata.cloudmgr.sdk.ApiException;
import cn.hashdata.cloudmgr.sdk.Configuration;
import cn.hashdata.cloudmgr.sdk.auth.*;
import cn.hashdata.cloudmgr.sdk.models.*;
import cn.hashdata.cloudmgr.sdk.api.CoreServiceApi;

public class Example {
    public static void main(String[] args) {
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("http://localhost:8000");
        
        // Configure OAuth2 access token for authorization: oauth2
        OAuth oauth2 = (OAuth) defaultClient.getAuthentication("oauth2");
        oauth2.setAccessToken("YOUR ACCESS TOKEN");

        CoreServiceApi apiInstance = new CoreServiceApi(defaultClient);
        String id = "id_example"; // String | 
        String startDate = "startDate_example"; // String | 
        String endDate = "endDate_example"; // String | 
        Integer offset = 56; // Integer | 
        Integer limit = 56; // Integer | 
        try {
            CoreListRecoveryResponse result = apiInstance.listRecoveries(id, startDate, endDate, offset, limit);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println("Exception when calling CoreServiceApi#listRecoveries");
            System.err.println("Status code: " + e.getCode());
            System.err.println("Reason: " + e.getResponseBody());
            System.err.println("Response headers: " + e.getResponseHeaders());
            e.printStackTrace();
        }
    }
}

Parameters

Name Type Description Notes
id String
startDate String [optional]
endDate String [optional]
offset Integer [optional]
limit Integer [optional]

Return type

CoreListRecoveryResponse

Authorization

oauth2

HTTP request headers

  • Content-Type: Not defined
  • Accept: /

HTTP response details

Status code Description Response headers
200 A successful response. -
400 Bad Request -
401 Unauthorized -
403 Forbidden -
404 Not Found -

监控

查询CPU使用率

GET select/1/prometheus/api/v1/query_range?query=collectd_cpu_percent{serviceid=”"}

查询内存使用率

GET select/1/prometheus/api/v1/query_range?query=collectd_memory_percent{memory="used”, serviceid=”"}

查询磁盘使用率

GET select/1/prometheus/api/v1/query_range?query=rate(collectd_disk_disk_io_time_io_time_total{serviceid=”"}[1m])/1000*100

查询SQL执行数

GET select/1/prometheus/api/v1/query_range?query=increase(service_workload_query_type_count_total{serviceid=”"}[1h] offset -1h)

查询数据库连接数

POST /webhook

{
    "subject":"string",
    "content":"string",
    "alert_type":"string",
    "description":"string",
    "healthStatus":"string",
    "serviceId":"string",
    "serviceName":"string",
    "serviceType":"string"
}

告警

向第三方webhook发送

POST /ops/api/v2/thirdpartyalert

{
  "subject" : "string",
  "content" : "string",
  "severity": "string"
  }

第三方通过cloudmgr消息

POST /ops/api/v2/thirdpartyalert

{
  "subject" : "string",
  "content" : "string",
  "severity": "string"
  }