华为云用户手册

  • 示例 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 CREATE OR REPLACE PROCEDURE proc_case_branch(pi_result in integer, pi_return out integer) AS BEGIN CASE pi_result WHEN 1 THEN pi_return := 111; WHEN 2 THEN pi_return := 222; WHEN 3 THEN pi_return := 333; WHEN 6 THEN pi_return := 444; WHEN 7 THEN pi_return := 555; WHEN 8 THEN pi_return := 666; WHEN 9 THEN pi_return := 777; WHEN 10 THEN pi_return := 888; ELSE pi_return := 999; END CASE; raise info 'pi_return : %',pi_return ; END; / CALL proc_case_branch(3,0); --删除存储过程 DROP PROCEDURE proc_case_branch;
  • FORALL批量查询语句 语法图 图5 forall::= 变量index会自动定义为integer类型并且只在此循环里存在。index的取值介于low_bound和upper_bound之间。 如果声明了SAVE EXCEPTIONS,则会将循环体DML执行过程中每次遇到的异常保存在SQL&BULK_EXCEPTIONS中,并在执行结束后统一抛出一个异常,循环过程中没有异常的执行的结果在当前子事务内不会回滚。 示例 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 CREATE TABLE hdfs_t1 ( title NUMBER(6), did VARCHAR2(20), data_period VARCHAR2(25), kind VARCHAR2(25), interval VARCHAR2(20), time DATE, isModified VARCHAR2(10) ); INSERT INTO hdfs_t1 VALUES( 8, 'Donald', 'OConnell', 'DOCONNEL', '650.507.9833', to_date('21-06-1999', 'dd-mm-yyyy'), 'SH_CLERK' ); CREATE OR REPLACE PROCEDURE proc_forall() AS BEGIN FORALL i IN 100..120 update hdfs_t1 set title = title + 100*i; END; / --调用函数 CALL proc_forall(); --查询存储过程调用结果 SELECT * FROM hdfs_t1 WHERE title BETWEEN 100 AND 120; --删除存储过程和表 DROP PROCEDURE proc_forall; DROP TABLE hdfs_t1;
  • 语法 创建函数时需要指定返回值SETOF datatype。 return_next_clause::= return_query_clause::= 对以上语法的解释如下: 当需要函数返回一个集合时,使用RETURN NEXT或者RETURN QUERY向结果集追加结果,然后继续执行函数的下一条语句。随着后续的RETURN NEXT或RETURN QUERY命令的执行,结果集中会有多个结果。函数执行完成后会一起返回所有结果。 RETURN NEXT可用于标量和复合数据类型。 RETURN QUERY有一种变体RETURN QUERY EXECUTE,后面还可以增加动态查询,通过USING向查询插入参数。
  • 示例 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 openGauss=# CREATE TABLE t1(a int); openGauss=# INSERT INTO t1 VALUES(1),(10); --RETURN NEXT openGauss=# CREATE OR REPLACE FUNCTION fun_for_return_next() RETURNS SETOF t1 AS $$ DECLARE r t1%ROWTYPE; BEGIN FOR r IN select * from t1 LOOP RETURN NEXT r; END LOOP; RETURN; END; $$ LANGUAGE PLPGSQL; openGauss=# call fun_for_return_next(); a --- 1 10 (2 rows) -- RETURN QUERY openGauss=# CREATE OR REPLACE FUNCTION fun_for_return_query() RETURNS SETOF t1 AS $$ DECLARE r t1%ROWTYPE; BEGIN RETURN QUERY select * from t1; END; $$ language plpgsql; openGauss=# call fun_for_return_query(); a --- 1 10 (2 rows)
  • 语法 语法请参见图1。 图1 call_anonymous_block::= using_clause子句的语法参见图2。 图2 using_clause::= 对以上语法格式的解释如下: 匿名块程序实施部分,以BEGIN语句开始,以END语句停顿,以一个分号结束。 USING [IN|OUT|IN OUT] bind_argument,用于指定存放传递给存储过程参数值的变量。bind_argument前的修饰符与对应参数的修饰符一致。 匿名块中间的输入输出参数使用占位符来指明,要求占位符个数与参数个数相同,并且占位符所对应参数的顺序和USING中参数的顺序一致。 目前 GaussDB 在动态语句调用匿名块时,EXCEPTION语句中暂不支持使用占位符进行输入输出参数的传递。
  • 语法 语法请参见图1。 图1 call_procedure::= using_clause子句的语法参见图2。 图2 using_clause::= 对以上语法格式的解释如下: CALL procedure_name: 调用存储过程。 [:placeholder1,:placeholder2,…]: 存储过程参数占位符列表。占位符个数与参数个数相同。 USING [IN|OUT|IN OUT] bind_argument: 用于指定存放传递给存储过程参数值的变量。bind_argument前的修饰符与对应参数的修饰符一致。
  • 示例 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 --创建表 openGauss=# CREATE TABLE sections_t1 ( section NUMBER(4) , section_name VARCHAR2(30), manager_id NUMBER(6), place_id NUMBER(4) ); --声明变量 openGauss=# DECLARE section NUMBER(4) := 280; section_name VARCHAR2(30) := 'Info support'; manager_id NUMBER(6) := 103; place_id NUMBER(4) := 1400; new_colname VARCHAR2(10) := 'sec_name'; BEGIN --执行查询 EXECUTE IMMEDIATE 'insert into sections_t1 values(:1, :2, :3, :4)' USING section, section_name, manager_id,place_id; --执行查询(重复占位符) EXECUTE IMMEDIATE 'insert into sections_t1 values(:1, :2, :3, :1)' USING section, section_name, manager_id; --执行ALTER语句(建议采用“||”拼接数据库对象构造DDL语句) EXECUTE IMMEDIATE 'alter table sections_t1 rename section_name to ' || new_colname; END; / --查询数据 openGauss=# SELECT * FROM sections_t1; --删除表 openGauss=# DROP TABLE sections_t1;
  • 语法 语法请参见图1。 图1 noselect::= using_clause子句的语法参见图2。 图2 using_clause::= 对以上语法格式的解释如下: USING IN bind_argument用于指定存放传递给动态SQL值的变量,在dynamic_noselect_string中存在占位符时使用,即动态SQL语句执行时,bind_argument将替换相对应的占位符。要注意的是,bind_argument只能是值、变量或表达式,不能是表名、列名、数据类型等数据库对象。如果存储过程需要通过声明参数传递数据库对象来构造动态SQL语句(常见于执行DDL语句时),建议采用连接运算符“||”拼接dynamic_select_clause。另外,动态语句允许出现重复的占位符,相同占位符只能与唯一一个bind_argument按位置一一对应。
  • EXECUTE IMMEDIATE 语法图请参见图1。 图1 EXECUTE IMMEDIATE dynamic_select_clause::= using_clause子句的语法图参见图2。 图2 using_clause::= 对以上语法格式的解释如下: define_variable:用于指定存放单行查询结果的变量。 USING IN bind_argument:用于指定存放传递给动态SQL值的变量,即在dynamic_select_string中存在占位符时使用。 USING OUT bind_argument:用于指定存放动态SQL返回值的变量。 查询语句中,into和out不能同时存在; 占位符命名以“:”开始,后面可跟数字、字符或字符串,与USING子句的bind_argument一一对应; bind_argument只能是值、变量或表达式,不能是表名、列名、数据类型等数据库对象,即不支持使用bind_argument为动态SQL语句传递模式对象。如果存储过程需要通过声明参数传递数据库对象来构造动态SQL语句(常见于执行DDL语句时),建议采用连接运算符“||”拼接dynamic_select_clause; 动态PL/SQL块允许出现重复的占位符,即相同占位符只能与USING子句的一个bind_argument按位置对应。
  • 示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 --创建存储过程proc_staffs openGauss=# CREATE OR REPLACE PROCEDURE proc_staffs ( section NUMBER(6), salary_sum out NUMBER(8,2), staffs_count out INTEGER ) IS BEGIN SELECT sum(salary), count(*) INTO salary_sum, staffs_count FROM hr.staffs where section_id = section; END; / --调用存储过程proc_return. openGauss=# CALL proc_staffs(2,8,6); --清除存储过程 openGauss=# DROP PROCEDURE proc_staffs;
  • 嵌套赋值 给变量嵌套赋值的语法请参见图2。 图2 nested_assignment_value::= 对以上语法格式的解释如下:图2 variable_name:变量名。 col_name:列名。 subscript:下标,针对数组变量使用,可以是值或表达式,类型必须为int。 value:可以是值或表达式。值value的类型需要和变量variable_name的类型兼容才能正确赋值。 示例: 1 2 3 4 5 6 7 8 9 openGauss=#CREATE TYPE o1 as (a int, b int); openGauss=# DECLARE TYPE r1 is VARRAY(10) of o1; emp_id r1; BEGIN emp_id(1).a := 5;--赋值 emp_id(1).b := 5*7784; END; /
  • 语法 给变量赋值的语法请参见图1。 图1 assignment_value::= 对以上语法格式的解释如下: variable_name:变量名。 value:可以是值或表达式。值value的类型需要和变量variable_name的类型兼容才能正确赋值。 示例: 1 2 3 4 5 6 7 openGauss=# DECLARE emp_id INTEGER := 7788;--赋值 BEGIN emp_id := 5;--赋值 emp_id := 5*7784; END; /
  • 变量声明 变量声明语法请参见图1。 图1 declare_variable::= 对以上语法格式的解释如下: variable_name:变量名。 type:变量类型。 value:该变量的初始值(如果不给定初始值,则初始为NULL)。value也可以是表达式。 示例 1 2 3 4 5 6 openGauss=# DECLARE emp_id INTEGER := 7788; --定义变量并赋值 BEGIN emp_id := 5*7784; --变量赋值 END; /
  • 基本语句 在编写PL/SQL过程中,会定义一些变量,给变量赋值,调用其他存储过程等。介绍PL/SQL中的基本语句,包括定义变量、赋值语句、调用语句以及返回语句。 尽量不要在存储过程中调用包含密码的SQL语句,因为存储在数据库中的存储过程文本可能被其他有权限的用户看到导致密码信息被泄漏。如果存储过程中包含其他敏感信息也需要配置存储过程的访问权限,保证敏感信息不会泄漏。 定义变量 赋值语句 调用语句 父主题: 存储过程
  • 结构 PL/SQL块中可以包含子块,子块可以位于PL/SQL中任何部分。PL/SQL块的结构如下: 声明部分:声明PL/SQL用到的变量、类型、游标、局部的存储过程和函数。 DECLARE 不涉及变量声明时声明部分可以没有。 对匿名块来说,没有变量声明部分时,可以省去DECLARE关键字。 对存储过程来说,没有DECLARE, AS相当于DECLARE。即便没有变量声明的部分,关键字AS也必须保留。 执行部分:过程及SQL语句,程序的主要部分。必选。 BEGIN 执行异常部分:错误处理。可选。 EXCEPTION 结束 END; / 禁止在PL/SQL块中使用连续的Tab,连续的Tab可能会造成在使用gsql工具带“-r”参数执行PL/SQL块时出现异常。
  • 示例 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 下面示例中用到的表定义如下: openGauss=# \d emp_rec Table "public.emp_rec" Column | Type | Modifiers ----------+--------------------------------+----------- empno | numeric(4,0) | not null ename | character varying(10) | job | character varying(9) | mgr | numeric(4,0) | hiredate | timestamp(0) without time zone | sal | numeric(7,2) | comm | numeric(7,2) | deptno | numeric(2,0) | --演示在函数中对数组进行操作。 openGauss=# CREATE OR REPLACE FUNCTION regress_record(p_w VARCHAR2) RETURNS VARCHAR2 AS $$ DECLARE --声明一个record类型. type rec_type is record (name varchar2(100), epno int); employer rec_type; --使用%type声明record类型 type rec_type1 is record (name emp_rec.ename%type, epno int not null :=10); employer1 rec_type1; --声明带有默认值的record类型 type rec_type2 is record ( name varchar2 not null := 'SCOTT', epno int not null :=10); employer2 rec_type2; CURSOR C1 IS select ename,empno from emp_rec order by 1 limit 1; BEGIN --对一个record类型的变量的成员赋值。 employer.name := 'WARD'; employer.epno = 18; raise info 'employer name: % , epno:%', employer.name, employer.epno; --将一个record类型的变量赋值给另一个变量。 employer1 := employer; raise info 'employer1 name: % , epno: %',employer1.name, employer1.epno; --将一个record类型变量赋值为NULL。 employer1 := NULL; raise info 'employer1 name: % , epno: %',employer1.name, employer1.epno; --获取record变量的默认值。 raise info 'employer2 name: % ,epno: %', employer2.name, employer2.epno; --在for循环中使用record变量 for employer in select ename,empno from emp_rec order by 1 limit 1 loop raise info 'employer name: % , epno: %', employer.name, employer.epno; end loop; --在select into 中使用record变量。 select ename,empno into employer2 from emp_rec order by 1 limit 1; raise info 'employer name: % , epno: %', employer2.name, employer2.epno; --在cursor中使用record变量。 OPEN C1; FETCH C1 INTO employer2; raise info 'employer name: % , epno: %', employer2.name, employer2.epno; CLOSE C1; RETURN employer.name; END; $$ LANGUAGE plpgsql; --调用该函数。 openGauss=# CALL regress_record('abc'); --删除函数。 openGauss=# DROP FUNCTION regress_record;
  • 示例 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 --演示在存储过程中对集合进行操作。 openGauss=# CREATE OR REPLACE PROCEDURE table_proc AS DECLARE TYPE TABLE_INTEGER IS TABLE OF INTEGER;--定义集合类型 TABLEINT TABLE_INTEGER := TABLE_INTEGER(); --声明集合类型的变量 BEGIN TABLEINT.extend(10); FOR I IN 1..10 LOOP TABLEINT(I) := I; END LOOP; DBE_OUTPUT.PRINT_LINE(TABLEINT.COUNT); DBE_OUTPUT.PRINT_LINE(TABLEINT(1)); DBE_OUTPUT.PRINT_LINE(TABLEINT(10)); END; / --调用该存储过程。 openGauss=# CALL table_proc(); --删除存储过程。 openGauss=# DROP PROCEDURE table_proc; --演示在存储过程中对嵌套集合进行操作。 openGauss=# CREATE OR REPLACE PROCEDURE nest_table_proc AS DECLARE TYPE TABLE_INTEGER IS TABLE OF INTEGER;--定义集合类型 TYPE NEST_TABLE_INTEGER IS TABLE OF TABLE_INTEGER;--定义集合类型 NEST_TABLE_VAR NEST_TABLE_INTEGER; --声明嵌套集合类型的变量 BEGIN FOR I IN 1..10 LOOP NEST_TABLE_VAR(I)(I) := I; END LOOP; DBE_OUTPUT.PRINT_LINE(NEST_TABLE_VAR.COUNT); DBE_OUTPUT.PRINT_LINE(NEST_TABLE_VAR(1)(1)); DBE_OUTPUT.PRINT_LINE(NEST_TABLE_VAR(10)(10)); END; / --调用该存储过程。 openGauss=# CALL nest_table_proc(); --删除存储过程。 openGauss=# DROP PROCEDURE nest_table_proc;
  • 数组类型的使用 在使用数组之前,需要自定义一个数组类型。 在存储过程中紧跟AS关键字后面定义数组类型。定义方法如下。 TYPE array_type IS VARRAY(size) OF data_type; 其中: array_type:要定义的数组类型名。 VARRAY:表示要定义的数组类型。 size:取值为正整数,表示可以容纳的成员的最大数量。 data_type:要创建的数组中成员的类型。 在GaussDB中,数组会自动增长,访问越界会返回一个NULL,不会报错。 在存储过程中定义的数组类型,其作用域仅在该存储过程中。 建议选择上述定义方法的一种来自定义数组类型,当同时使用两种方法定义同名的数组类型时,GaussDB会优先选择存储过程中定义的数组类型来声明数组变量。 data_type也可以为存储过程中定义的record类型(匿名块不支持),但不可以为存储过程中定义的数组或集合类型。 GaussDB支持使用圆括号来访问数组元素,且还支持一些特有的函数,如extend、count、first、last、prior、exists、 trim、next、delete来访问数组的内容。 存储过程中如果有DML语句(SELECT、UPDATE、INSERT、DELETE),DML语句推荐使用中括号来访问数组元素,使用小括号默认识别为数组访问,若数组不存在,则识别为函数表达式。 慎用delete删除单个元素功能,会造成元素顺序错乱。 如果clob类型大于1GB,则存储过程中的table of类型、record类型、clob作为出入参、游标、raise info等功能不支持。
  • 示例 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 --演示在存储过程中对数组进行操作。 openGauss=# CREATE OR REPLACE PROCEDURE array_proc AS DECLARE TYPE ARRAY_INTEGER IS VARRAY(1024) OF INTEGER;--定义数组类型 ARRINT ARRAY_INTEGER := ARRAY_INTEGER(); --声明数组类型的变量 BEGIN ARRINT.extend(10); FOR I IN 1..10 LOOP ARRINT(I) := I; END LOOP; DBE_OUTPUT.PRINT_LINE(ARRINT.COUNT); DBE_OUTPUT.PRINT_LINE(ARRINT(1)); DBE_OUTPUT.PRINT_LINE(ARRINT(10)); DBE_OUTPUT.PRINT_LINE(ARRINT(ARRINT.FIRST)); DBE_OUTPUT.PRINT_LINE(ARRINT(ARRINT.LAST)); DBE_OUTPUT.PRINT_LINE(ARRINT(ARRINT.NEXT(ARRINT.FIRST))); DBE_OUTPUT.PRINT_LINE(ARRINT(ARRINT.PRIOR(ARRINT.LAST))); ARRINT.TRIM(); IF ARRINT.EXISTS(10) THEN DBE_OUTPUT.PRINT_LINE('Exist 10th element'); ELSE DBE_OUTPUT.PRINT_LINE('Not exist 10th element'); END IF; DBE_OUTPUT.PRINT_LINE(ARRINT.COUNT); DBE_OUTPUT.PRINT_LINE(ARRINT(ARRINT.FIRST)); DBE_OUTPUT.PRINT_LINE(ARRINT(ARRINT.LAST)); ARRINT.DELETE(); END; / --调用该存储过程。 openGauss=# CALL array_proc(); --删除存储过程。 openGauss=# DROP PROCEDURE array_proc;
  • 数据类型转换 数据库中允许有些数据类型进行隐式类型转换(赋值、函数调用的参数等),有些数据类型间不允许进行隐式数据类型转换,可尝试使用GaussDB提供的类型转换函数,例如CAST进行数据类型强转。 GaussDB数据库 常见的隐式类型转换,请参见表1。 GaussDB支持的DATE的效限范围是:公元前4713年到公元294276年。 表1 隐式类型转换表 原始数据类型 目标数据类型 备注 CHAR VARCHAR2 - CHAR NUMBER 原数据必须由数字组成。 CHAR DATE 原数据不能超出合法日期范围。 CHAR RAW - CHAR CLOB - VARCHAR2 CHAR - VARCHAR2 NUMBER 原数据必须由数字组成。 VARCHAR2 DATE 原数据不能超出合法日期范围。 VARCHAR2 CLOB - NUMBER CHAR - NUMBER VARCHAR2 - DATE CHAR - DATE VARCHAR2 - RAW CHAR - RAW VARCHAR2 - CLOB CHAR - CLOB VARCHAR2 - CLOB NUMBER 原数据必须由数字组成。 INT4 CHAR - INT4 BOOLEAN - BOOLEAN INT4 - 父主题: 存储过程
  • 扩展语法 GaussDB提供的扩展语法如下。 表1 扩展SQL语法 类别 语法关键字 描述 创建表CREATE TABLE INHERITS ( parent_table [, ... ] ) 目前保留继承表语法,但是不支持继承表。 column_constraint: REFEREN CES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ][ ON DELETE action ] [ ON UPDATE action ] 支持用REFERENCES reftable[ ( refcolumn ) ] [ MATCH FULL |MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] 为表创建外键约束。 加载模块 CREATE EXTENSION 把一个新的模块加载进当前数据库中。 DROP EXTENSION 删除已加载的模块。 聚集函数 CREATE AGGREGATE 定义一个新的聚集函数。 ALTER AGGREGATE 修改一个聚集函数的定义。 DROP AGGREGATE 删除一个现存的聚集函数。 父主题: 附录
  • 扩展函数 下表列举了GaussDB中支持的扩展函数,不作为商用特性交付,仅供参考。 分类 函数名称 描述 访问权限查询函数 has_sequence_privilege(user, sequence, privilege) 指定用户是否有访问序列的权限 has_sequence_privilege(sequence, privilege) 当前用户是否有访问序列的权限 触发器函数 pg_get_triggerdef(oid) 为触发器获取CREATE [ CONSTRAINT ] TRIGGER命令 pg_get_triggerdef(oid, boolean) 为触发器获取CREATE [ CONSTRAINT ] TRIGGER命令 父主题: 附录
  • GIN提示与技巧 创建vs插入 由于可能要为每个项目插入很多键,所以GIN索引的插入可能比较慢。对于向表中大量插入的操作,我们建议先删除GIN索引,在完成插入之后再重建索引。与GIN索引创建、查询性能相关的GUC参数如下: maintenance_work_mem GIN索引的构建时间对maintenance_work_mem的设置非常敏感。 work_mem 在向启用了FASTUPDATE的GIN索引执行插入操作的期间,只要待处理实体列表的大小超过了work_mem,系统就会清理这个列表。为了避免可观察到的响应时间的大起大落,让待处理实体列表在后台被清理是比较合适的(比如通过autovacuum)。前端清理操作可以通过增加work_mem或者执行autovacuum来避免。然而,扩大work_mem意味着如果发生了前端清理,那么他的执行时间将更长。 gin_fuzzy_search_limit 开发GIN索引的主要目的是为了让GaussDB支持高度可伸缩的全文索引,并且常常会遇见全文索引返回海量结果的情形。而且,这经常发生在查询高频词的时候,因而这样的结果集没什么用处。因为从磁盘读取大量记录并对其进行排序会消耗大量资源,这在产品环境下是不能接受的。为了控制这种情况,GIN索引有一个可配置的返回结果行数的软上限的配置参数gin_fuzzy_search_limit。缺省值0表示没有限制。如果设置了非零值,那么返回结果就是从完整结果集中随机选择的一部分。"软上限"的意思是返回结果的实际数量可能与指定的限制有偏差,这取决于查询和系统随机数生成器的质量。 父主题: GIN索引
  • 部分匹配算法 GIN可以支持“部分匹配”查询。即:查询并不决定单个或多个键的一个精确的匹配,而是,可能的匹配落在一个合理的狭窄键值范围内(根据compare支持函数决定的键值排序顺序)。此时,extractQuery方法并不返回一个用于精确匹配的键值,取而代之的是,返回一个要被搜索的键值范围的下边界,并且设置pmatch为true。然后,使用comparePartial方式扫描这个键值范围。comparePartial必须为一个相匹配的索引键返回0,如果不匹配但依然在被搜索范围内时返回小于0的值,对超过可以匹配的范围的索引键则返回大于0的值。
  • GIN快速更新技术 由于倒排索引的本身特性影响,更新一个GIN索引可能会比较慢。插入或更新一个堆行可能导致许多往索引的插入。当对表执行VACUUM后,或者如果待处理实体的列表太大了(大于work_mem),这些实体被使用和初始索引创建时用到的相同的bulk插入方法,移动到主要的GIN数据结构。即使把额外的VACUUM开销算进去,这也大大提升了GIN索引更新的速度。而且,这种额外开销的工作可以通过后台进程而不是前端查询来处理。 这种方法的主要缺点在于搜索时除了常规的索引还必须要扫描待处理实体的列表。因此,大的待处理实体的列表会显著的拖慢搜索。另一个缺点是,虽然大多数更新很快,但是一个导致待处理列表(pending list)变得“太大”的更新将引发一个立即清理,并因此比起其它更新会非常慢。恰当的使用autovacuum可以弱化这两个问题。 如果一致的响应时间(清理实体速度和更新速度的响应时间)比更新速度更重要,可以通过把GIN索引的存储参数FASTUPDATE设置为off而不使用待处理实体。详细请参考CREATE INDEX。
  • 扩展性 GIN索引的接口实现了一个高层次的抽象,要求访问用户仅需要实现被访问数据类型的语义。GIN层自身可以处理并发操作、记录日志、搜索树结构的任务。 定义GIN索引的访问方式所要做的事情就是实现多个用户定义的方法,这些方法定义了键在树中的行为、键与键之间的关系、需要索引的item、能够使用索引的查询。简而言之,GIN索引将扩展性与普遍性、代码重用、清晰的接口结合在了一起。 实现GIN索引的操作符类有如下四个方法: int compare(Datum a, Datum b) 比较两个key(不是索引的item)然后返回一个小于零、零或大于零的值,分别表示第一个key小于、等于或大于第二个key。NULL不会被传入这个函数。 Datum *extractValue(Datum itemValue, int32 *nkeys, bool **nullFlags) 给定一个要被索引的item,返回一个对应key的数组。返回key的数组必须存储在*nkeys中。如果任何key都可能为NULL,还要分配包含*nkeys个布尔元素的数组,将地址存储到*nullFlags,并且根据需要设置NULL值。 如果所有key都是非NULL,可以让*nullFlags保持为NULL(他的初始值)。如果item不包含任何key,返回值可以为NULL。 Datum *extractQuery(Datum query, int32 *nkeys, StrategyNumber n, bool **pmatch, Pointer **extra_data, bool **nullFlags, int32 *searchMode) 给定一个被查询的值,返回一个对应的key的数组。也就是说,query是可索引操作符右侧的值,而该操作符左侧是被索引的字段。 n是操作符类中操作符的策略号。通常,extractQuery需要参考n来决定query的数据类型以及抽取键值的方法。返回key的个数必须存放在*nkeys中。如果任何key都可能为NULL,还要分配包含*nkeys个布尔元素的数组,将地址存储到*nullFlags,并且根据需要设置NULL值。 如果所有key都是非NULL的,可以让*nullFlags保持为NULL(他的初始值)。如果query不包含任何key,返回值可以为NULL。 searchMode是一个输出参数,他允许extractQuery指定一些关于如何执行搜索的细节。如果设置*searchMode为GIN_SEARCH_MODE_DEFAULT(这也是调用函数前此参数的初始化值),只有那些至少返回一个key的item才能被考虑作为候选匹配项。如果设置*searchMode为GIN_SEARCH_MODE_INCLUDE_EMPTY,除了包含至少一个匹配key的item之外,根本不包含任何key的item也被考虑作为候选匹配项。(这个模式对于实现像“是否是子集”这样的操作是有用的)如果设置*searchMode为GIN_SEARCH_MODE_ALL,索引中所有非NULL的item都被考虑作为候选匹配项,不管他们是否匹配返回key中的任何一个。 pmatch是一个允许支持部分匹配的输出参数。如果使用此参数,extractQuery必须分配有*nkeys个布尔元素的数组,并把数组地址保存到*pmatch。如果需要部分匹配相应的key,则数组的每个元素应该设置为TRUE;如果不需要匹配,则设置为FALSE。如果设置*pmatch为NULL,则假设GIN不需要部分匹配。在函数调用前这个值被初始化为NULL,因此,对于不支持部分匹配的操作符类,可以忽略这个参数。 extra_data是一个允许extractQuery以consistent和comparePartial的方式传递额外数据的输出参数。如果使用他,extractQuery必须分配一个包含*nkeys个Pointer元素的数组,并把数组地址保存到*extra_data,然后把他想附加的东西存储到各个独立的指针中。在函数调用前这个值初始化为NULL,因此,对于不需要附加数据的操作符类,可以忽略这个参数。如果设置了*extra_data,那么以consistent方式传递整个数组,使用comparePartial方式传递适当的元素。 bool consistent(bool check[], StrategyNumber n, Datum query, int32 nkeys, Pointer extra_data[], bool *recheck, Datum queryKeys[], bool nullFlags[]) 如果被索引项满足StrategyNumber为n的查询操作符则返回TRUE。这个函数并不直接访问被索引项的值,因为GIN并没有精确的把项目保存下来,但是需要知道从查询中提取的哪些键值出现在给定的被索引项中。 check数组的长度是nkeys,这个与query调用extractQuery函数返回的键值的数目相同。如果索引项包含了相应的查询键,check数组中对应的元素值就是TRUE。比如,如果(check[i] == TRUE),那么意味着extractQuery的结果数组的第i个键出现在索引项中。考虑可能会用到consistent方式,原始的query也被作为参数传入进来。与此相同的还有extractQuery函数返回的queryKeys[]和nullFlags[]。 extra_data是extractQuery函数返回的额外数据数组,如果没有的话就是NULL。 当extractQuery在queryKeys[]中返回一个NULL的键值,如果被索引项包含NULL键值,相应的check[]中的元素是TRUE。也就是说,check[]的语义很像IS NOT DISTINCT FROM。如果需要知道是通常值匹配还是NULL匹配,consistent函数可以检查相应的nullFlags[]元素。 成功执行后,如果堆元组需要针对查询运算符进行重新检查,*recheck需要设置为TRUE,如果索引测试已经是精确的了,则设为FALSE。也就是说,FALSE的返回值确保堆元组不匹配这个查询;设置*recheck为FALSE的TRUE的返回值确保堆元组匹配这个查询;设置*recheck为TRUE的TRUE的返回值意味着堆元组可能匹配这个查询,因此需要通过直接对照原始索引项对查询运算符进行获取和重新检查。 GIN操作符类可以可选地提供第五个函数。 int comparePartial(Datum partial_key, Datum key, StrategyNumber n, Pointer extra_data) 比较一个部分匹配查询键和一个索引键。返回一个整型值,它的符号代表了不同的含义:小于0意味着索引键不匹配查询,但是索引扫描应该继续; 0意味着索引键匹配查询;大于0指示应该终止索引扫描,因为不可能再有更多的匹配。在需要确定何时结束扫描的语义的情况下,这里提供了生成部分一致查询的操作符的策略号n。同样的,extra_data是extractQuery生成的额外数据数组中的相应元素,如果没有对应的元素,则为NULL。 NULL的键永远不会被传入这个函数。 为了支持"部分匹配"查询,一个操作符类必须提供comparePartial方法,并且当遇到部分匹配查询时,他的extractQuery方法必须设置pmatch参数。详细信息请参考部分匹配算法。 上面的各种Datum值的实际数据类型根据操作符类的不同而不同。传入到extractValue中的项目值总是操作符类的输入类型,所有的键值类型必须是这个类的STORAGE类型。传入到extractQuery和consistent的query参数的类型是由策略号识别的类成员操作符的右操作数的输入类型。他不需要和项目类型相同,只要可以从中抽取出正确类型的键值。 父主题: GIN索引
  • 介绍 GIN(Generalized Inverted Index)通用倒排索引。设计为处理索引项为组合值的情况,查询时需要通过索引搜索出出现在组合值中的特定元素值。例如,文档是由多个单词组成,需要查询出文档中包含的特定单词。 使用item表示索引的组合值,key表示一个元素值。GIN用来存储和搜索key,而不是item。 GIN索引存储一系列(key,posting list)键值对,这里的posting list是一组出现key的行ID。由于每个item都可能包含多个key,同一个行ID可能会出现在多个posting list中,而每个key值只被存储一次,所以在相同的key在item中出现多次的情况下,GIN索引是非常简洁的。 因为GIN索引的访问方式不需要了解他的运行方式,所以GIN索引是通用的。GIN索引使用为特殊数据类型定义的策略。策略定义了如何从索引选项和查询条件中抽出key,以及如何确定在查询中包含某些key值的行是否实际满足查询条件。 父主题: GIN索引
  • 语法格式 VALUES {( expression [, ...] )} [, ...] [ ORDER BY { sort_expression [ ASC | DESC | USING operator ] } [, ...] ] [ LIMIT { count | ALL } ] [ OFFSET start [ ROW | ROWS ] ] [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ];
  • 参数说明 expression 用于计算或插入结果表指定地点的常量或者表达式。 在一个出现在INSERT顶层的VALUES列表中,expression可以被DEFAULT替换以表示插入目的字段的缺省值。除此以外,当VALUES出现在其他场合的时候是不能使用DEFAULT的。 sort_expression 一个表示如何排序结果行的表达式或者整数常量。 ASC 指定按照升序排列。 DESC 指定按照降序排列。 operator 一个排序操作符。 count 返回的最大行数。 OFFSET start { ROW | ROWS } 声明返回的最大行数,而start声明开始返回行之前忽略的行数。 FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY FETCH子句限定返回查询结果从第一行开始的总行数,count的缺省值为1。
  • 示例 --在表tpcds.reason上创建索引。 openGauss=# CREATE UNIQUE INDEX ds_reason_index1 ON tpcds.reason(r_reason_sk); --对带索引的表tpcds.reason执行VACUUM操作。 openGauss=# VACUUM (VERBOSE, ANALYZE) tpcds.reason; --删除索引。 openGauss=# DROP INDEX ds_reason_index1 CASCADE; openGauss=# DROP TABLE tpcds.reason;
共100000条