华为云用户手册

  • ODBC接口参考 ODBC接口是一套提供给用户的API函数,本节将对部分常用接口做具体描述,若涉及其他接口可参考msdn(网址:https://msdn.microsoft.com/en-us/library/windows/desktop/ms714177(v=vs.85).aspx)中ODBC Programmer's Reference项的相关内容。 SQLAllocEnv SQLAllocConnect SQLAllocHandle SQLAllocStmt SQLBindCol SQLBindParameter SQLColAttribute SQLConnect SQLDisconnect SQLExecDirect SQLExecute SQLFetch SQLFreeStmt SQLFreeConnect SQLFreeHandle SQLFreeEnv SQLPrepare SQLGetData SQLGetDiagRec SQLSetConnectAttr SQLSetEnvAttr SQLSetStmtAttr 父主题: 基于ODBC开发
  • 常用方法 表1 PGReplicationConnection常用方法 返回值 方法 描述 throws ChainedCreateReplicationSlotBuilder createReplicationSlot() 用于创建逻辑复制槽 - void dropReplicationSlot(String slotName) 用于删除逻辑复制槽 SQLException,IOException ChainedStreamBuilder replicationStream() 用户开启逻辑复制 -
  • PGReplicationConnection的继承关系 PGReplicationConnection是逻辑复制的接口,实现类是PGReplicationConnectionImpl,该类位于org.postgresql.replication Package中,该类的声明如下: public class PGReplicationConnection implements PGReplicationConnection
  • javax.sql.PooledConnection javax.sql.PooledConnection是由连接池创建的连接接口。 表1 对javax.sql.PooledConnection的支持情况 方法名 返回值类型 支持JDBC 4 addConnectionEventListener (ConnectionEventListener listener) void Yes close() void Yes getConnection() Connection Yes removeConnectionEventListener (ConnectionEventListener listener) void Yes 父主题: JDBC接口参考
  • java.sql.Statement java.sql.Statement是SQL语句接口。 表1 对java.sql.Statement的支持情况 方法名 返回值类型 支持JDBC 4 addBatch(String sql) void Yes clearBatch() void Yes clearWarnings() void Yes close() void Yes closeOnCompletion() void Yes execute(String sql) Boolean Yes execute(String sql, int autoGeneratedKeys) Boolean Yes execute(String sql, int[] columnIndexes) Boolean Yes execute(String sql, String[] columnNames) Boolean Yes executeBatch() Boolean Yes executeQuery(String sql) ResultSet Yes executeUpdate(String sql) int Yes executeUpdate(String sql, int autoGeneratedKeys) int Yes executeUpdate(String sql, int[] columnIndexes) int Yes executeUpdate(String sql, String[] columnNames) int Yes getConnection() Connection Yes getFetchDirection() int Yes getFetchSize() int Yes getGeneratedKeys() ResultSet Yes getMaxFieldSize() int Yes getMaxRows() int Yes getMoreResults() boolean Yes getMoreResults(int current) boolean Yes getResultSet() ResultSet Yes getResultSetConcurrency() int Yes getResultSetHoldability() int Yes getResultSetType() int Yes getQueryTimeout() int Yes getUpdateCount() int Yes getWarnings() SQLWarning Yes isClosed() Boolean Yes isCloseOnCompletion() Boolean Yes isPoolable() Boolean Yes setCursorName(String name) void Yes setEscapeProcessing(boolean enable) void Yes setFetchDirection(int direction) void Yes setMaxFieldSize(int max) void Yes setMaxRows(int max) void Yes setPoolable(boolean poolable) void Yes setQueryTimeout(int seconds) void Yes setFetchSize(int rows) void Yes cancel() void Yes executeLargeUpdate(String sql) long No getLargeUpdateCount() long No executeLargeBatch() long No executeLargeUpdate(String sql, int autoGeneratedKeys) long No executeLargeUpdate(String sql, int[] columnIndexes) long No executeLargeUpdate(String sql, String[] columnNames) long No 通过setFetchSize可以减少结果集在客户端的内存占用情况。它的原理是通过将结果集打包成游标,然后分段处理,所以会加大数据库与客户端的通信量,会有性能损耗。 由于数据库游标是事务内有效,所以,在设置setFetchSize的同时,需要将连接设置为非自动提交模式,setAutoCommit(false)。同时在业务数据需要持久化到数据库中时,在连接上执行提交操作。 LargeUpdate相关方法必须在JDBC4.2及以上使用。 父主题: JDBC接口参考
  • 获取结果集中光标的位置 对于可滚动的结果集,可能会调用定位方法来改变光标的位置。JDBC驱动程序提供了获取结果集中光标所处位置的方法。获取光标位置的方法如表3所示。 表3 获取结果集光标的位置 方法 描述 isFirst() 是否在第一行。 isLast() 是否在最后一行。 isBeforeFirst() 是否在第一行之前。 isAfterLast() 是否在最后一行之后。 getRow() 获取当前在第几行。
  • 在结果集中定位 ResultSet对象具有指向其当前数据行的光标。最初,光标被置于第一行之前。next方法将光标移动到下一行;因为该方法在ResultSet对象没有下一行时返回false,所以可以在while循环中使用它来迭代结果集。但对于可滚动的结果集,JDBC驱动程序提供更多的定位方法,使ResultSet指向特定的行。定位方法如表2所示。 表2 在结果集中定位的方法 方法 描述 next() 把ResultSet向下移动一行。 previous() 把ResultSet向上移动一行。 beforeFirst() 把ResultSet定位到第一行之前。 afterLast() 把ResultSet定位到最后一行之后。 first() 把ResultSet定位到第一行。 last() 把ResultSet定位到最后一行。 absolute(int) 把ResultSet移动到参数指定的行数。 relative(int) 通过设置为1向前(设置为1,相当于next())或者向后(设置为-1,相当于previous())移动参数指定的行。
  • 设置结果集类型 不同类型的结果集有各自的应用场景,应用程序需要根据实际情况选择相应的结果集类型。在执行SQL语句过程中,都需要先创建相应的语句对象,而部分创建语句对象的方法提供了设置结果集类型的功能。具体的参数设置如表1所示。涉及的Connection的方法如下: 1 2 3 4 5 6 7 8 //创建一个Statement对象,该对象将生成具有给定类型和并发性的ResultSet对象。 createStatement(int resultSetType, int resultSetConcurrency); //创建一个PreparedStatement对象,该对象将生成具有给定类型和并发性的ResultSet对象。 prepareStatement(String sql, int resultSetType, int resultSetConcurrency); //创建一个CallableStatement对象,该对象将生成具有给定类型和并发性的ResultSet对象。 prepareCall(String sql, int resultSetType, int resultSetConcurrency); 表1 结果集类型 参数 描述 resultSetType 表示结果集的类型,具体有三种类型: ResultSet.TYPE_FORWARD_ONLY:ResultSet只能向前移动。是缺省值。 ResultSet.TYPE_SCROLL_SENSITIVE:在修改后重新滚动到修改所在行,可以看到修改后的结果。 ResultSet.TYPE_SCROLL_INSENSITIVE:对可修改例程所做的编辑不进行显示。 说明: 结果集从数据库中读取了数据之后,即使类型是ResultSet.TYPE_SCROLL_SENSITIVE,也不会看到由其他事务在这之后引起的改变。调用ResultSet的refreshRow()方法,可进入数据库并从其中取得当前游标所指记录的最新数据。 resultSetConcurrency 表示结果集的并发,具体有两种类型: ResultSet.CONCUR_READ_ONLY:如果不从结果集中的数据建立一个新的更新语句,不能对结果集中的数据进行更新。 ResultSet.CONCUR_UPDATEABLE:可改变的结果集。对于可滚动的结果集,可对结果集进行适当的改变。
  • 获取结果集中的数据 ResultSet对象提供了丰富的方法,以获取结果集中的数据。获取数据常用的方法如表4所示,其他方法请参考JDK官方文档。 表4 ResultSet对象的常用方法 方法 描述 int getInt(int columnIndex) 按列标获取int型数据。 int getInt(String columnLabel) 按列名获取int型数据。 String getString(int columnIndex) 按列标获取String型数据。 String getString(String columnLabel) 按列名获取String型数据。 Date getDate(int columnIndex) 按列标获取Date型数据 Date getDate(String columnLabel) 按列名获取Date型数据。
  • 示例 注:示例1和示例2选择其一。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 // 认证用的用户名和密码直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中存放(密码应密文存放,使用时解密),确保安全; // 本示例以用户名和密码保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量(环境变量名称请根据自身情况进行设置)EXAMPLE_USERNAME_ENV和EXAMPLE_PASSWORD_ENV。 public class SSL{ public static void main(String[] args) { Properties urlProps = new Properties(); String urls = "jdbc:postgresql://$ip:$port/postgres"; String userName = System.getenv("EXAMPLE_USERNAME_ENV"); String password = System.getenv("EXAMPLE_PASSWORD_ENV"); /** * ================== 示例1 使用NonValidatingFactory通道 */ urlProps.setProperty("sslfactory","org.postgresql.ssl.NonValidatingFactory"); urlProps.setProperty("user", userName); urlProps.setProperty("password", password); urlProps.setProperty("ssl", "true"); /** * ================== 示例2 使用证书 */ urlProps.setProperty("sslcert", "client.crt"); urlProps.setProperty("sslkey", "client.key.pk8"); urlProps.setProperty("sslrootcert", "cacert.pem"); urlProps.setProperty("user", userName); urlProps.setProperty("ssl", "true"); /* sslmode可配置为:require、verify-ca、verify-full,以下三个示例选择其一*/ /* ================== 示例2.1 设置sslmode为require,使用证书 */ urlProps.setProperty("sslmode", "require"); /* ================== 示例2.2 设置sslmode为verify-ca,使用证书 */ urlProps.setProperty("sslmode", "verify-ca"); /* ================== 示例2.3 设置sslmode为verify-full,使用证书(Linux下验证) */ urls = "jdbc:postgresql://world:8000/postgres"; urlProps.setProperty("sslmode", "verify-full"); try { Class.forName("org.postgresql.Driver").newInstance(); } catch (Exception e) { e.printStackTrace(); } try { Connection conn; conn = DriverManager.getConnection(urls,urlProps); conn.close(); } catch (Exception e) { e.printStackTrace(); } } } /** * 注:将客户端密钥转化为DER格式: * openssl pkcs8 -topk8 -outform DER -in client.key -out client.key.pk8 -nocrypt * openssl pkcs8 -topk8 -inform PEM -in client.key -outform DER -out client.key.der -v1 PBE-MD5-DES * openssl pkcs8 -topk8 -inform PEM -in client.key -outform DER -out client.key.der -v1 PBE-SHA1-3DES * 以上算法由于安全级别较低,不推荐使用。 * 如果客户需要采用更高级别的私钥加密算法,启用bouncycastle或者其他第三方私钥解密密码包后可以使用的私钥加密算法如下: * openssl pkcs8 -in client.key -topk8 -outform DER -out client.key.der -v2 AES128 * openssl pkcs8 -in client.key -topk8 -outform DER -out client.key.der -v2 aes-256-cbc -iter 1000000 * openssl pkcs8 -in client.key -topk8 -out client.key.der -outform Der -v2 aes-256-cbc -v2prf hmacWithSHA512 * 启用bouncycastle:使用jdbc的项目引入依赖:bcpkix-jdk15on.jar包,版本建议:1.65以上。 */
  • 驱动类 在创建数据库连接之前,需要加载数据库驱动类“org.postgresql.Driver”(对应包gsjdbc4.jar)。 由于 GaussDB 在JDBC的使用上与PG的使用方法保持兼容,所以同时在同一进程内使用两个JDBC的驱动的时候,可能会类名冲突。 本版本JDBC不再支持 IAM 认证功能。 相比于PG驱动,GaussDB JDBC驱动主要做了以下特性的增强: 支持SHA256加密方式登录。 支持对接实现sf4j接口的第三方日志框架。 支持连接级别的分布式负载均衡。 支持容灾切换。
  • 环境类 客户端需配置JDK1.8。JDK是跨平台的,支持Windows、Linux等多种平台,下面以Windows为例,介绍JDK配置流程: DOS窗口(windows下的命令提示符)输入“java -version”,查看JDK版本,确认为JDK1.8版本。如果未安装JDK,请下载安装包并安装。 在windows操作系统桌面中“此电脑”图标上单击右键,选择“属性”。 在弹出的“系统”窗口中,单击左侧导航栏中“高级系统设置”。 在弹出的“系统属性”窗口中,单击右下角的“环境变量”。 在弹出的“环境变量”窗口中的“系统变量”区域框中设置如下变量名和变量值。 变量名 操作 变量值 JAVA_HOME 若存在,则单击“编辑”。 若不存在,则单击“新建”。 JAVA的安装目录。 例如:C:\Program Files\Java\jdk1.8.0_131 Path 编辑 若配置了JAVA_HOME,则在变量值的最前面加上: %JAVA_HOME%\bin; 若未配置JAVA_HOME,则在变量值的最前面加上 JAVA安装的全路径: C:\Program Files\Java\jdk1.8.0_131\bin; CLASSPATH 新建 .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar; 单击“确定”,并依次关闭各窗口。
  • JDBC包 从发布包中获取。包名为GaussDB-Kernel_VxxxRxxxCxx-操作系统版本号-64bit-Jdbc.tar.gz。 解压后JDBC的驱动jar包: gsjdbc4.jar:该驱动包适用于从PostgreSQL迁移业务的场景,驱动类和加载路径与迁移前保持一致,但接口支持情况不完全一致,未支持的接口需要业务侧进行调整。 opengaussjdbc.jar:主类名为“com.huawei.opengauss.jdbc.Driver”,数据库连接的url前缀为“jdbc:opengauss”,推荐使用此驱动包。如果遇到同一JVM进程内需要同时访问PostgreSQL及GaussDB的场景,请使用此驱动包。 各驱动包只是驱动类加载路径和url前缀不同,接口功能上相同。 jdbc发布件jar包按照架构分类,gscejdbc.jar包必须与对应的部署环境一致才能使用,其他jar包无需与部署环境一致。 gsjdbc200.jar:该驱动包适用于从Gauss200迁移业务的场景,驱动类和加载路径与迁移前保持一致,但接口支持情况不完全一致,未支持的接口需要业务侧进行调整。 不能使用gsjdbc4的驱动包操作PostgreSQL数据库,虽然部分版本能够建连成功,但部分接口行为与PostgreSQL JDBC不同,可能导致未知错误。 不能使用PostgreSQL的驱动包操作 GaussDB数据库 ,虽然部分版本能够建连成功,但部分接口行为与GaussDB JDBC不同,可能导致未知错误。
  • 选择数据类型 在字段设计时,基于查询效率的考虑,一般遵循以下原则: 【建议】尽量使用高效数据类型。 选择数值类型时,在满足业务精度的情况下,选择数据类型的优先级从高到低依次为整数、浮点数、NUMERIC。 【建议】当多个表存在逻辑关系时,表示同一含义的字段应该使用相同的数据类型。 【建议】对于字符串数据,建议使用变长字符串数据类型,并指定最大长度。请务必确保指定的最大长度大于需要存储的最大字符数,避免超出最大长度时出现字符截断现象。除非明确知道数据类型为固定长度字符串,否则,不建议使用CHAR(n)、BPCHAR(n)、NCHAR(n)、CHARACTER(n)。 关于字符串类型的详细说明,请参见常用字符串类型介绍。
  • 选择分布键 分布表的分布键选取至关重要,如果分布键选择不当,可能会导致数据倾斜,从而导致查询时,I/O负载集中在部分DN上,影响整体查询性能。因此,在确定分布表的分布策略之后,需要对表数据进行倾斜性检查,以确保数据的均匀分布。分布键的选择一般需要遵循以下原则: 【建议】选作分布键的字段取值应该比较离散,以便数据能在各个DN上均匀分布。当单个字段无法满足离散条件时,可以考虑使用多个字段一起作为分布键。一般情况下,可以考虑选择表的主键作为分布键。例如,在人员信息表中选择证件号码作为分布键。 【建议】在满足第一条原则的情况下,尽量不要选取在查询中存在常量过滤条件的字段作为分布键。例如,在表dwcjk相关的查询中,字段zqdh存在常量过滤条件“zqdh='000001'”,那么就应当尽量不选择zqdh字段作为分布键。 【建议】在满足前两条原则的情况,尽量选择查询中的关联条件为分布键。当关联条件作为分布键时,join任务的相关数据都分布在DN本地,将极大减少DN之间的数据流动代价。
  • 选择分区方案 当表中的数据量很大时,应当对表进行分区,一般需要遵循以下原则: 【建议】使用具有明显区间性的字段进行分区,比如日期、区域等字段上建立分区。 【建议】分区名称应当体现分区的数据特征。例如,关键字+区间特征。 【建议】将分区上边界的分区值定义为MAXVALUE,以防止可能出现的数据溢出。 典型的分区表定义如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CREATE TABLE staffS_p1 ( staff_ID NUMBER(6) not null, FIRST_NAME VARCHAR2(20), LAST_NAME VARCHAR2(25), EMAIL VARCHAR2(25), PHONE_NUMBER VARCHAR2(20), HIRE_DATE DATE, employment_ID VARCHAR2(10), SALARY NUMBER(8,2), COMMISSION_PCT NUMBER(4,2), MANAGER_ID NUMBER(6), section_ID NUMBER(4) ) PARTITION BY RANGE (HIRE_DATE) ( PARTITION HIRE_19950501 VALUES LESS THAN ('1995-05-01 00:00:00'), PARTITION HIRE_19950502 VALUES LESS THAN ('1995-05-02 00:00:00'), PARTITION HIRE_maxvalue VALUES LESS THAN (MAXVALUE) );
  • 选择分布方案 【建议】表的分布方式的选择一般遵循以下原则: 表2 表的分布方式及使用场景 分布方式 描述 适用场景 Hash 表数据通过Hash方式散列到集群中的所有DN上。 数据量较大的事实表。 Replication 集群中每一个DN都有一份全量表数据。 维度表、数据量较小的事实表。 Range 表数据对指定列按照范围进行映射,分布到对应DN。 用户需要自定义分布规则的场景。 List 表数据对指定列按照具体值进行映射,分布到对应DN。 用户需要自定义分布规则的场景。 当指定Hash、Range或List分布时,创建主键和唯一索引必须包含分布列。 典型的分布表定义如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 --定义一个表,表中每行存在所有DN中。 CREATE TABLE warehouse_d1 ( W_WAREHOUSE_SK INTEGER NOT NULL, W_WAREHOUSE_ID CHAR(16) NOT NULL, W_WAREHOUSE_NAME VARCHAR(20) , W_WAREHOUSE_SQ_FT INTEGER , W_STREET_NUMBER CHAR(10) , W_STREET_NAME VARCHAR(60) , W_STREET_TYPE CHAR(15) , W_SUITE_NUMBER CHAR(10) , W_CITY VARCHAR(60) , W_COUNTY VARCHAR(30) , W_STATE CHAR(2) , W_ZIP CHAR(10) , W_COUNTRY VARCHAR(20) , W_GMT_OFFSET DECIMAL(5,2) )DISTRIBUTE BY REPLICATION; --定义一个表,使用HASH分布。 CREATE TABLE warehouse_d2 ( W_WAREHOUSE_SK INTEGER NOT NULL, W_WAREHOUSE_ID CHAR(16) NOT NULL, W_WAREHOUSE_NAME VARCHAR(20) , W_WAREHOUSE_SQ_FT INTEGER , W_STREET_NUMBER CHAR(10) , W_STREET_NAME VARCHAR(60) , W_STREET_TYPE CHAR(15) , W_SUITE_NUMBER CHAR(10) , W_CITY VARCHAR(60) , W_COUNTY VARCHAR(30) , W_STATE CHAR(2) , W_ZIP CHAR(10) , W_COUNTRY VARCHAR(20) , W_GMT_OFFSET DECIMAL(5,2), CONSTRAINT W_CONSTR_KEY3 UNIQUE(W_WAREHOUSE_SK) )DISTRIBUTE BY HASH(W_WAREHOUSE_SK); --定义一个表,使用RANGE分布 CREATE TABLE warehouse_d3 ( W_WAREHOUSE_SK INTEGER NOT NULL, W_WAREHOUSE_ID CHAR(16) NOT NULL, W_WAREHOUSE_NAME VARCHAR(20) , W_WAREHOUSE_SQ_FT INTEGER , W_STREET_NUMBER CHAR(10) , W_STREET_NAME VARCHAR(60) , W_STREET_TYPE CHAR(15) , W_SUITE_NUMBER CHAR(10) , W_CITY VARCHAR(60) , W_COUNTY VARCHAR(30) , W_STATE CHAR(2) , W_ZIP CHAR(10) , W_COUNTRY VARCHAR(20) , W_GMT_OFFSET DECIMAL(5,2) )DISTRIBUTE BY RANGE(W_WAREHOUSE_ID) ( SLICE s1 VALUES LESS THAN (10) DATANODE dn1, SLICE s2 VALUES LESS THAN (20) DATANODE dn2, SLICE s3 VALUES LESS THAN (30) DATANODE dn3, SLICE s4 VALUES LESS THAN (MAXVALUE) DATANODE dn4 ); --定义一个表,使用LIST分布 CREATE TABLE warehouse_d4 ( W_WAREHOUSE_SK INTEGER NOT NULL, W_WAREHOUSE_ID CHAR(16) NOT NULL, W_WAREHOUSE_NAME VARCHAR(20) , W_WAREHOUSE_SQ_FT INTEGER , W_STREET_NUMBER CHAR(10) , W_STREET_NAME VARCHAR(60) , W_STREET_TYPE CHAR(15) , W_SUITE_NUMBER CHAR(10) , W_CITY VARCHAR(60) , W_COUNTY VARCHAR(30) , W_STATE CHAR(2) , W_ZIP CHAR(10) , W_COUNTRY VARCHAR(20) , W_GMT_OFFSET DECIMAL(5,2) )DISTRIBUTE BY LIST(W_COUNTRY) ( SLICE s1 VALUES ('USA') DATANODE dn1, SLICE s2 VALUES ('CANADA') DATANODE dn2, SLICE s3 VALUES ('UK') DATANODE dn3, SLICE s4 VALUES (DEFAULT) DATANODE dn4 );
  • 数据库对象命名 数据库对象命名需要满足约束: 标识符表长度不超过63个字节。 标识符以字母或下划线开头,中间字符可以是字母、数字、下划线、$、#。 若标识符被双引号("")包含,则可以使用合法字符的任意组合,如"123gs_column"。 标识符不区分大小写,只有被双引号包含才区分大小写。 【建议】避免使用保留或者非保留关键字命名数据库对象。 可以使用select * from pg_get_keywords()查询GaussDB的关键字,或者在关键字章节中查看。 【建议】避免使用双引号括起来的字符串来定义数据库对象名称,除非需要限制数据库对象名称的大小写。数据库对象名称大小写敏感会使定位问题难度增加。 【建议】数据库对象命名风格务必保持统一。 增量开发的业务系统或进行业务迁移的系统,建议遵守历史的命名风格。 建议使用多个单词组成,以下划线分割。 数据库对象名称建议能够望文知意,尽量避免使用自定义缩写(可以使用通用的术语缩写进行命名)。例如,在命名中可以使用具有实际业务含义的英文词汇或汉语拼音,但规则应该在集群范围内保持一致。 变量名的关键是要具有描述性,即变量名称要有一定的意义,变量名要有前缀标明该变量的类型。 【建议】表对象的命名应该可以表征该表的重要特征。例如,在表对象命名时区分该表是普通表、临时表还是非日志表: 普通表名按照数据集的业务含义命名。 临时表以“tmp_+后缀”命名。 非日志表以“ul_+后缀”命名。 不创建以redis_为前缀的数据库对象。 不创建以mlog_和以matviewmap_为前缀的数据库对象。 【建议】表对象命名建议不要超过63字节。如果超过该长度内核会对表名进行截断,从而出现实际名称和设置值不一致的现象;且在不同字符集下,可能造成字符被截断,出现预期外的字符。 父主题: 开发设计建议
  • 背景信息 当客户在使用数据库过程中,如果白天执行一些耗时比较长的任务(例如:统计数据汇总之类或从其他数据库同步数据的任务),会对正常的业务有性能影响,所以客户经常选择在晚上执行,无形中增加了客户的工作量。因此数据库兼容Orcale数据库中定时任务的功能,可以由客户创建定时任务,当任务时间点到达后可以自动触发任务的执行,从而可以减少客户运维的工作量。 数据库兼容Oracle定时任务功能主要通过DBE_TASK高级包提供的接口,可以实现定时任务的创建、任务到期自动执行、任务删除、修改任务属性(包括:任务id、任务的关闭开启、任务的触发时间、触发时间间隔、任务内容等)。
  • 定时任务管理 创建测试表: 1 openGauss=# CREATE TABLE test(id int, time date); 当结果显示为如下信息,则表示创建成功。 1 CREATE TABLE 创建自定义存储过程: 1 2 3 4 5 6 7 8 9 openGauss=# CREATE OR REPLACE PROCEDURE PRC_JOB_1() AS N_NUM integer :=1; BEGIN FOR I IN 1..1000 LOOP INSERT INTO test VALUES(I,SYSDATE); END LOOP; END; / 当结果显示为如下信息,则表示创建成功。 1 CREATE PROCEDURE 创建任务: 新创建的任务(未指定job_id)表示每隔1分钟执行一次存储过程PRC_JOB_1。 1 2 3 4 5 openGauss=# call dbe_task.submit('call public.prc_job_1(); ', sysdate, 'interval ''1 minute''', :a); job ----- 1 (1 row) 指定job_id创建任务,其中job_id可用范围为1~32767。 1 2 3 4 5 openGauss=# call dbe_task.id_submit(2,'call public.prc_job_1(); ', sysdate, 'interval ''1 minute'''); isubmit --------- (1 row) 通过视图查看当前用户已创建的任务信息。 1 2 3 4 5 openGauss=# select job,dbname,start_date,last_date,this_date,next_date,broken,status,interval,failures,what from my_jobs; job | dbname | start_date | last_date | this_date | next_date | broken | status | interval | failures | what -----+--------+---------------------+----------------------------+----------------------------+---------------------+--------+--------+---------------------+----------+--------------------------- 1 | testdb | 2017-07-18 11:38:03 | 2017-07-18 13:53:03.607838 | 2017-07-18 13:53:03.607838 | 2017-07-18 13:54:03 | n | s | interval '1 minute' | 0 | call public.prc_job_1(); (1 row) 停止任务。 1 2 3 4 5 openGauss=# call dbe_task.finish(1,true); broken -------- (1 row) 启动任务。 1 2 3 4 5 openGauss=# call dbe_task.finish(1,false); broken -------- (1 row) 修改任务属性: 修改JOB的Next_date参数信息。 --修改Job1的Next_date为1小时以后开始执行。 1 2 3 4 5 openGauss=# call dbe_task.next_time(1, sysdate+1.0/24); next_date ----------- (1 row) 修改JOB的Interval参数信息。 --修改Job1的Interval为每隔1小时执行一次。 1 2 3 4 5 openGauss=# call dbe_task.interval(1,'sysdate + 1.0/24'); interval ---------- (1 row) 修改JOB的What参数信息。 --修改Job1的What为执行SQL语句“insert into public.test values(333, sysdate+5);”。 1 2 3 4 5 openGauss=# call dbe_task.content(1,'insert into public.test values(333, sysdate+5);'); what ------ (1 row) 同时修改JOB的Next_date、Interval、What等多个参数信息。 1 2 3 4 5 openGauss=# call dbe_task.update(1, 'call public.prc_job_1();', sysdate, 'interval ''1 minute'''); change -------- (1 row) 删除JOB。 1 2 3 4 5 openGauss=# call dbe_task.cancel(1); remove -------- (1 row) 查看JOB执行情况。 当JOB自动执行时,如果JOB执行失败(即job_status状态值为'f')时,用户可以通过查看当前JOB所属CN的数据目录的pg_log子目录下对应时间点的运行日志来查看JOB的失败信息。 日志信息如下所示,从失败信息(detail error msg)中可以查看失败的具体错误。 LOG : Execute Job Detail: job_id: 1 what: call public.test(); start_date: 2017-07-19 23:30:47.401818 job_status: failed detail error msg: relation "test" does not exist end_date: 2017-07-19 23:30:47.401818 next_run_date: 2017-07-19 23:30:56.855827 JOB的权限控制: 当创建一个JOB时,该JOB会和创建该JOB的数据库和用户绑定(即:pg_job系统表新增的JOB记录中的dbname和log_user)。 如果当前用户是DBA用户、系统管理员、该JOB的创建用户(即:pg_job中的log_user),那么该用户有权限通过高级包接口remove、change、next_data、what、interval删除或修改JOB的参数信息。否则,会提示当前用户没有权限操作该JOB。 如果当前数据库是该JOB创建所属的数据库(即:为pg_job系统表中的dbname),那么连接到当前数据库上可以通过高级包接口cancel、update、next_data、content、interval删除或修改JOB的参数信息。 当删除JOB所属的数据库(即:为pg_job系统表中的dbname)时,系统会关联删除该数据库从属的JOB记录。 当删除JOB所属的用户(即:为pg_job系统表中的log_user)时,系统会关联删除该用户从属的JOB记录。 JOB的并发控制管理。 用户可以通过配置GUC参数job_queue_processes来调整并发同时执行的JOB数目。 当job_queue_processes设置为0值,表示不启用定时任务功能,任何job都不会被执行。 当job_queue_processes为大于0时,表示启用定时任务功能且系统能够并发处理的最大任务数。 由于并行运行的任务数太多会消耗更多的系统资源,因此需要设置系统并发处理的任务数,当前并发的任务数达到job_queue_processes时,且此时又有任务到期,那么这些任务本次得不到执行而延期到下一轮询周期。因此,建议用户需要根据每个任务的执行时长合理地设置任务的时间间隔(即submit接口中的interval参数),来避免由于任务执行时间太长而导致下个轮询周期无法正常执行。 注:对于不使用JOB的集群中,用户可以通过在集群安装初始化完成后,通过设置job_queue_processes为0来关闭JOB功能,减少系统资源的消耗。
  • 背景信息 索引可以提高数据的访问速度,但同时也增加了插入、更新和删除操作的处理时间。所以是否要为表增加索引,索引建立在哪些字段上,是创建索引前必须要考虑的问题。需要分析应用程序的业务处理、数据使用、经常被用作查询的条件或者被要求排序的字段来确定是否建立索引。 索引建立在数据库表中的某些列上。因此,在创建索引时,应该仔细考虑在哪些列上创建索引。 在经常需要搜索查询的列上创建索引,可以加快搜索的速度。 在作为主键的列上创建索引,强制该列的唯一性和组织表中数据的排列结构。 在经常使用连接的列上创建索引,可以加快连接的速度。 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的。 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间。 在经常使用WHERE子句的列上创建索引,加快条件的判断速度。 为经常出现在关键字ORDER BY、GROUP BY、DISTINCT后面的字段建立索引。 索引创建成功后,系统会自动判断何时引用索引。当系统认为使用索引比顺序扫描更快时,就会使用索引。 索引创建成功后,必须和表保持同步以保证能够准确地找到新数据,这样就增加了数据操作的负荷。因此请定期删除无用的索引。
  • 查看数据库中包含的表 在public Schema下新建五张表: openGauss=# CREATE TABLE public.search_table_t1(a int) distribute by hash(a); CREATE TABLE openGauss=# CREATE TABLE public.search_table_t2(b int) distribute by hash(b); CREATE TABLE openGauss=# CREATE TABLE public.search_table_t3(c int) distribute by hash(c); CREATE TABLE openGauss=# CREATE TABLE public.search_table_t4(d int) distribute by hash(d); CREATE TABLE openGauss=# CREATE TABLE public.search_table_t5(e int) distribute by hash(e); CREATE TABLE 在PG_TABLES系统表中查看public Schema中包含的前缀为search_table的表。 1 openGauss=# SELECT distinct(tablename) FROM pg_tables WHERE SCHEMANAME = 'public' AND TABLENAME LIKE 'search_table%'; 结果类似如下这样: 1 2 3 4 5 6 7 8 tablename ----------------- search_table_t1 search_table_t2 search_table_t3 search_table_t4 search_table_t5 (5 rows)
  • 查看数据库用户 通过PG_USER可以查看数据库中所有用户的列表,还可以查看用户ID(USESYSID)和用户权限。 1 SELECT * FROM pg_user; 1 2 3 4 5 6 usename | usesysid | usecreatedb | usesuper | usecatupd | userepl | passwd | valbegin | valuntil | respool | parent | spacelimit | useconfig | nodegroup | tempspacelimit | spillspacelimit ---------+----------+-------------+----------+-----------+---------+----------+----------+----------+--------------+------ -------+------------+-----------+-----------+----------------+----------------- roach | 10 | t | t | t | t | ******** | | | default_pool | 0 | | | | | (1 row)
  • 查看和停止正在运行的查询语句 通过视图PG_STAT_ACTIVITY可以查看正在运行的查询语句。方法如下: 设置参数track_activities为on。 1 SET track_activities = on; 当此参数为on时,数据库系统才会收集当前活动查询的运行信息。 查看正在运行的查询语句。以查看正在运行的查询语句所连接的数据库名、执行查询的用户、查询状态及查询对应的PID为例: 1 SELECT datname, usename, state,pid FROM pg_stat_activity; 1 2 3 4 5 6 7 8 datname | usename | state | pid ----------+---------+--------+----------------- testdb | Ruby | active | 140298793514752 testdb | Ruby | active | 140298718004992 testdb | Ruby | idle | 140298650908416 testdb | Ruby | idle | 140298625742592 testdb | omm | active | 140298575406848 (5 rows) 如果state字段显示为idle,则表明此连接处于空闲,等待用户输入命令。 如果仅需要查看非空闲的查询语句,则使用如下命令查看: 1 SELECT datname, usename, state, pid FROM pg_stat_activity WHERE state != 'idle'; 若需要取消运行时间过长的查询,通过PG_TERMINATE_BACKEND函数,根据线程ID(即2中查询结果的pid字段)结束会话。 1 SELECT PG_TERMINATE_BACKEND(140298793514752); 显示类似如下信息,表示结束会话成功。 1 2 3 4 PG_TERMINATE_BACKEND ---------------------- t (1 row) 显示类似如下信息,表示用户执行了结束当前会话的操作。 1 2 FATAL: terminating connection due to administrator command FATAL: 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,无法结束会话。非线程池模式下,结束的会话不会自动重连。
  • 更新表中数据 修改已经存储在数据库中数据的行为叫做更新。用户可以更新单独一行,所有行或者指定的部分行。还可以独立更新每个字段,而其他字段则不受影响。 使用UPDATE命令更新现有行,需要提供以下三种信息: 表的名称和要更新的字段名 字段的新值 要更新哪些行 SQL通常不会为数据行提供唯一标识,因此无法直接声明需要更新哪一行。但是可以通过声明一个被更新的行必须满足的条件。只有在表里存在主键的时候,才可以通过主键指定一个独立的行。 建立表和插入数据的步骤请参考创建表和向表中插入数据。 需要将表customer_t1中c_customer_sk为9527的地域重新定义为9876: 1 openGauss=# UPDATE customer_t1 SET c_customer_sk = 9876 WHERE c_customer_sk = 9527; 这里的表名称也可以使用模式名修饰,否则会从默认的模式路径找到这个表。SET后面紧跟字段和新的字段值。新的字段值不仅可以是常量,也可以是变量表达式。 比如,把所有c_customer_sk的值增加100: 1 openGauss=# UPDATE customer_t1 SET c_customer_sk = c_customer_sk + 100; 在这里省略了WHERE子句,表示表中的所有行都要被更新。如果出现了WHERE子句,那么只有匹配其条件的行才会被更新。 在SET子句中的等号是一个赋值,而在WHERE子句中的等号是比较。WHERE条件不一定是相等测试,许多其他的操作符也可以使用。 用户可以在一个UPDATE命令中更新更多的字段,方法是在SET子句中列出更多赋值,比如: 1 openGauss=# UPDATE customer_t1 SET c_customer_id = 'Admin', c_first_name = 'Local' WHERE c_customer_sk = 4421; 批量更新或删除数据后,会在数据文件中产生大量的删除标记,查询过程中标记删除的数据也是需要扫描的。故多次批量更新/删除后,标记删除的数据量过大会严重影响查询的性能。建议在批量更新/删除业务会反复执行的场景下,定期执行VACUUM FULL以保持查询性能。 父主题: 创建和管理表
  • 搜索路径 搜索路径定义在search_path参数中,参数取值形式为采用逗号分隔的Schema名称列表。如果创建对象时未指定目标Schema,则该对象将会被添加到搜索路径中列出的第一个Schema中。当不同Schema中存在同名的对象时,查询对象未指定Schema的情况下,将从搜索路径中包含该对象的第一个Schema中返回对象。 要查看当前搜索路径,请使用SHOW。 1 2 3 4 5 openGauss=# SHOW SEARCH_PATH; search_path ---------------- "$user",public (1 row) search_path参数的默认值为:"$user",public。$user表示与当前会话用户名同名的Schema名,如果这样的模式不存在,$user将被忽略。所以默认情况下,用户连接数据库后,如果数据库下存在同名Schema,则对象会添加到同名Schema下,否则对象被添加到Public Schema下。 要更改当前会话的默认Schema,请使用SET命令。 执行如下命令将搜索路径设置为myschema,public,首先搜索myschema,然后搜索public。 1 2 openGauss=# SET SEARCH_PATH TO myschema, public; SET
  • 创建、修改和删除Schema 要创建Schema,请使用CREATE SCHEMA。默认初始用户和系统管理员可以创建Schema,其他用户需要具备数据库的CREATE权限才可以在该数据库中创建Schema,赋权方式请参考GRANT中将数据库的访问权限赋予指定的用户或角色中的语法。 要更改Schema名称或者所有者,请使用ALTER SCHEMA。Schema所有者可以更改Schema。 要删除Schema及其对象,请使用DROP SCHEMA。Schema所有者可以删除Schema。 要在Schema内创建表,请以schema_name.table_name格式创建表。不指定schema_name时,对象默认创建到搜索路径中的第一个Schema内。 要查看Schema所有者,请对系统表PG_NAMESPACE和PG_USER执行如下关联查询。语句中的schema_name请替换为实际要查找的Schema名称。 1 openGauss=# SELECT s.nspname,u.usename AS nspowner FROM pg_namespace s, pg_user u WHERE nspname='schema_name' AND s.nspowner = u.usesysid; 要查看所有Schema的列表,请查询PG_NAMESPACE系统表。 1 openGauss=# SELECT * FROM pg_namespace; 要查看属于某Schema下的表列表,请查询系统视图PG_TABLES。例如,以下查询会返回Schema PG_CATALOG中的表列表。 1 openGauss=# SELECT distinct(tablename),schemaname from pg_tables where schemaname = 'pg_catalog';
  • 内置角色 GaussDB提供了一组默认角色,以gs_role_开头命名。它们提供对特定的、通常需要高权限的操作的访问,可以将这些角色GRANT给数据库内的其他用户或角色,让这些用户能够使用特定的功能。在授予这些角色时应当非常小心,以确保它们被用在需要的地方。表1描述了内置角色允许的权限范围: 表1 内置角色权限描述 角色 权限描述 gs_role_copy_files 具有执行copy … to/from filename 的权限,但需要先打开GUC参数enable_copy_server_files。 gs_role_signal_backend 具有调用函数pg_cancel_backend、pg_terminate_backend和pg_terminate_session来取消或终止其他会话的权限,但不能操作属于初始用户和PERSISTENCE用户的会话。 gs_role_tablespace 具有创建表空间(tablespace)的权限。 gs_role_replication 具有调用逻辑复制相关函数的权限,例如kill_snapshot、pg_create_logical_replication_slot、pg_create_physical_replication_slot、pg_drop_replication_slot、pg_replication_slot_advance、pg_create_physical_replication_slot_extern、pg_logical_slot_get_changes、pg_logical_slot_peek_changes、pg_logical_slot_get_binary_changes、pg_logical_slot_peek_binary_changes。 gs_role_account_lock 具有加解锁用户的权限,但不能加解锁初始用户和PERSISTENCE用户。 gs_role_pldebugger 具有执行dbe_pldebugger下调试函数的权限。 gs_role_directory_create 具有执行创建directory对象的权限,但需要先打开GUC参数enable_access_server_directory。 gs_role_directory_drop 具有执行删除directory对象的权限,但需要先打开GUC参数enable_access_server_directory。 关于内置角色的管理有如下约束: 以gs_role_开头的角色名作为数据库的内置角色保留名,禁止新建以“gs_role_”开头的用户/角色,也禁止将已有的用户/角色重命名为以“gs_role_”开头; 禁止对内置角色的ALTER和DROP操作; 内置角色默认没有LOGIN权限,不设预置密码; gsql元命令\du和\dg不显示内置角色的相关信息,但若显示指定了pattern为特定内置角色则会显示。 三权分立关闭时,初始用户、具有SYSADMIN权限的用户和具有内置角色ADMIN OPTION权限的用户有权对内置角色执行GRANT/REVOKE管理。三权分立打开时,初始用户和具有内置角色ADMIN OPTION权限的用户有权对内置角色执行GRANT/REVOKE管理。例如: 1 2 GRANT gs_role_signal_backend TO user1; REVOKE gs_role_signal_backend FROM user1;
  • 创建、修改和删除角色 非三权分立时,只有系统管理员和具有CREATEROLE属性的用户才能创建、修改或删除角色。三权分立下,只有初始用户和具有CREATEROLE属性的用户才能创建、修改或删除角色。 要创建角色,请使用CREATE ROLE。 要在现有角色中添加或删除用户,请使用ALTER ROLE。 要删除角色,请使用DROP ROLE。DROP ROLE只会删除角色,并不会删除角色中的成员用户帐户。
  • 安全策略管理员 安全策略管理员是指具有POLADMIN属性的账户,具有创建资源标签、脱敏策略和统一审计策略的权限。 要创建新的安全策略管理员,请以系统管理员用户身份连接数据库,并使用带POLADMIN选项的CREATE USER语句或 ALTER USER语句进行设置。 1 openGauss=# CREATE USER poladmin WITH POLADMIN password "********"; 或者 1 openGauss=# ALTER USER joe POLADMIN; ALTER USER时,要求用户已存在。
共100000条