华为云用户手册

  • 支持的数据类型以及接口 数据库支持数字,字符串,时间等多种类型。目前C函数支持的类型,以及各种类型的C类型和SQL类型的对应关系,类型的参数获取以及返回结果的接口,见下表: 表1 C类型和SQL类型的对应关系 SQL类型 C类型 获取参数 返回结果 varchar VarChar* PG_GETARG_DATUM PG_RETURN_VARCHAR_P text text* PG_GETARG_DATUM PG_RETURN_TEXT_P char BpChar* PG_GETARG_DATUM PG_RETURN_BPCHAR_P date DateADT PG_GETARG_DATUM PG_RETURN_DATEADT timestamp Timestamp PG_GETARG_TIMESTAMP PG_RETURN_TIMESTAMP smallint int16 PG_GETARG_INT16 PG_RETURN_INT16 integer int32 PG_GETARG_INT32 PG_RETURN_INT32 bigint int64 PG_GETARG_INT64 PG_RETURN_INT64 常用函数及说明见下表: 表2 常用函数及说明 函数名 功能 TextDatumGetCString 传入text/varchar/bpchar的Datum类型,返回一个char*字符串 cstring_to_text 转换char*字符串到text/varchar类型 date_pl_interval date类型加一个时间间隔 timestamp_pl_interval timestamp类型加一个时间间隔 int4_numeric integer数据转换成numeric类型 palloc 内存申请 pfree 内存释放 PointerGetDatum 指针类型强制转换成Datum类型 DirectFunctionCall1 调用1个参数的函数 DirectFunctionCall2 调用2个参数的函数 DirectFunctionCall3 调用3个参数的函数 PG_ARGISNULL(N) 判断函数的第n个参数是否为NULL
  • 编写代码 C语言函数的编写需要遵守基本的规则: 函数声明语法,Datum funcname(PG_FUNCTION_ARGS)。 申明函数是版本1格式,调用宏PG_FUNCTION_INFO_V1(funcname)。不使用宏则默认为版本0格式。 C文件中声明PG_MODULE_MAGIC,标记数据库的版本信息,防止动态库被加载到一个不兼容的服务器。 在分配内存时,使用函数palloc和pfree,而不是使用对应的C库函数malloc和free。在每个事务结束是会自动释放通过palloc申请的内存,以免内存泄露。 C文件中定义的符号名不能相互冲突或者与服务器中可执行程序中定义的符号冲突。如果有关于此的编译错误消息,你必须重命名你的函数或者变量。 开发者应充分了解要调用的内核函数接口功能及入参范围,在调用前应检查参数合法性,避免出现空指针等可能导致程序crash的问题。 自定义函数上线前应经过充分测试,避免引入问题影响数据库正常业务。
  • 创建C函数 以ISNUMBER为例: 1234 create or replace function isnumber(text)returns integeras '...../isNumber.so', 'ISNUMBER'language c strict fenced IMMUTABLE SHIIPABLE; ...../isNumber.so 指定了库文件的路径。当enable_default_cfunc_libpath打开时,只需要指定文件名即可,数据库会自动在默认目录($libdir/proc_srclib)下查找该文件。当enable_default_cfunc_libpath关闭时,这里必须指定库文件的绝对路径。enable_default_cfunc_libpath参数默认打开。 属性strict,表示只要其中任意参数为NULL值,该函数就会返回空值,当有NULL参数时该函数不会被执行,而是自动返回一个空值结果。也就是说,如果函数创建时没有指定strict属性,则函数的C语言实现一定要对参数是否为NULL特殊处理,例如:maxdate的实现。否则,对NULL的不正确的使用可能引起进程的crash。 属性fenced,如果指定函数为fenced模式,则函数会在worker进程中被调用,防止C代码实现错误导致服务器crash,不建议使用not fenced模式。 属性IMMUTABLE,表示函数的结果只倚赖于它的输入参数。 属性SHIPPABLE,表示这个函数可以下推到DN执行。对于IMMUTABLE类型的函数,如果函数的返回值类型不是record,则可以下推到DN上执行。 对于STABLE/VOLATILE类型的函数,仅当函数的属性是SHIPPABLE的时候,函数可以下推到DN执行。 函数属性在CREATE FUNCTION章节会有详细介绍。
  • 示例 示例1:函数功能,返回两个时间中的较大的,文件名maxtimestamp.cpp,文件内容如下。 其中,PG_GETARG_TIMESTAMP(0)、PG_GETARG_TIMESTAMP(1)分别获取timestamp类型的第一个参数和第二个参数。PG_ARGISNULL(0)、PG_ARGISNULL(1)返回参数1、参数2是否为NULL。PG_RETURN_TIMESTAMP返回timestamp结果。
  • 编译生成动态库 在使用用户定义的C代码之前,必须编译链接生成一个能被服务器动态载入的文件。确切的说,需要生成一个共享库文件。 首先源文件被编译成一个目标文件,然后目标文件被连接起来。目标文件需要被创建成position-independent code (PIC),这意味着当它们被载入时,可以被放置在内存中的任意位置。 下面例子中,我们以文件isNumber.c为例,并且创建一个共享库isNumber.so。 Linux创建PIC的编译器标志是-fpic。在不同平台上的,需要参考GCC手册。创建一个共享库的编译器标志是-shared。一个完整的例子: gcc -fpic -c isNumber.cpp -I include/postgresql/server/gcc -shared -o isNumber.so isNumber.o 上述命令也可以连在一起: gcc -shared -fpic -o isNumber.so isNumber.cpp -I include/postgresql/server/ 其中include/postgresql/server/ 为服务器对外发布的头文件路径,在安装目录下面。 gcc版本要求在7.3.0或者7.3.0之上。 为保证C函数兼容性,若涉及数据库升级,用户需要基于升级后的头文件重新编译C函数共享库。 在服务端加载过动态库后,不可在环境上手动修改该动态库,否则可能出现段错误或其他未知问题。
  • 示例 1 2 3 4 5 6 7 8 91011121314151617181920212223242526272829303132333435 --演示在存储过程中对数组进行操作。gaussdb=# CREATE OR REPLACE PROCEDURE array_proc ASDECLARE 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; /--调用该存储过程。gaussdb=# CALL array_proc();--删除存储过程。gaussdb=# DROP PROCEDURE array_proc;
  • 数组类型的使用 在使用数组之前,需要自定义一个数组类型。 在存储过程中紧跟AS关键字后面定义数组类型。定义方法为: TYPE array_type IS VARRAY(size) OF data_type; 其中: array_type:要定义的数组类型名。 VARRAY:表示要定义的数组类型。 size:取值为正整数,表示可以容纳的成员的最大数量。 data_type:要创建的数组中成员的类型。 在GaussDB中,数组会自动增长,访问越界会返回一个NULL,不会报错。 在存储过程中定义的数组类型,其作用域仅在该存储过程中。 size只支持语法,不支持功能。 data_type也可以为存储过程中定义的record类型(匿名块不支持)、集合类型,但不可以为存储过程中定义的数组类型、游标类型。 data_type为集合类型时,不支持使用多维数组。 不支持NOT NULL语法。 array类型的构造器仅支持在ORA兼容模式下使用。 不支持array类型的构造器作为函数或存储过程参数的默认值。 当data_type为varchar、numeric等可以定义长度和精度的类型,如果package内创建varray类型数组,则在package外部调用该varray类型数组时,varchar、numeric等长度或精度限制会失效。 GaussDB支持使用圆括号来访问数组元素,且还支持一些特有的函数,如extend,count,first,last, prior, next, exists, trim, delete来访问数组的内容。 存储过程中如果有DML语句(SELECT、UPDATE、INSERT、DELETE),DML语句只能使用中括号来访问数组元素,这样可以和函数表达式区分开。
  • 数据类型转换 数据库中允许有些数据类型进行隐式类型转换(赋值、函数调用的参数等),有些数据类型间不允许进行隐式数据类型转换,可尝试使用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 - 父主题: 存储过程
  • 存储过程 商业规则和业务逻辑可以通过程序存储在GaussDB中,这个程序就是存储过程。 存储过程是SQL、PL/SQL、Java语句的组合。存储过程使执行商业规则的代码可以从应用程序中移动到数据库。从而,代码存储一次能够被多个程序使用。 存储过程的创建及调用办法请参考CREATE PROCEDURE。 PL/pgSQL语言函数节所提到的PL/pgSQL语言创建的函数与存储过程的应用方法相通。下面各节中,除非特别声明,否则内容通用于存储过程和PL/pgSQL语言函数。 父主题: 存储过程
  • 美元引用的字符串常量 如果在字符串序列中包含有'(单引号),那么应当将'(单引号)加倍为''(两个单引号)否则sql语句很可能无法执行。 如果字符串中包含很多单引号或者反斜杠,那么理解字符串的内容可能就会变得很苦涩,并且容易出错,因为单引号都要加倍。 为了让这种场合下的查询更具可读性,我们允许另外一种称作"美元符界定"的字符串常量书写办法。一个通过美元符界定声明的字符串常量由一个美元符号($)、零个或多个字符组成的"记号"、另一个美元符号、组成字符串常量的任意字符序列、一个美元符号、与前面相同的记号、一个美元符号组成的。 gaussdb=# select $$it's an example$$; ?column? ----------------- it's an example(1 row) 父主题: 附录
  • 场景一:磁盘满后快速定位存储倾斜的表 首先,通过pg_stat_get_last_data_changed_time(oid)函数查询出近期发生过数据变更的表,鉴于表的最后修改时间只在进行IUD操作的CN记录,要查询库内1天(间隔可在函数中调整)内被修改的所有表,可以使用如下封装函数: 1 2 3 4 5 6 7 8 9101112131415161718192021 CREATE OR REPLACE FUNCTION get_last_changed_table(OUT schemaname text, OUT relname text) RETURNS setof record AS $$ DECLARE row_data record; row_name record; query_str text; query_str_nodes text; BEGIN query_str_nodes := 'SELECT node_name FROM pgxc_node where node_type = ''C'''; FOR row_name IN EXECUTE(query_str_nodes) LOOP query_str := 'EXECUTE DIRECT ON (' || row_name.node_name || ') ''SELECT b.nspname,a.relname FROM pg_class a INNER JOIN pg_namespace b on a.relnamespace = b.oid where pg_stat_get_last_data_changed_time(a.oid) BETWEEN current_timestamp - 1 AND current_timestamp;'''; FOR row_data IN EXECUTE(query_str) LOOP schemaname = row_data.nspname; relname = row_data.relname; return next; END LOOP; END LOOP; return; END; $$ LANGUAGE 'plpgsql'; 然后,通过table_distribution(schemaname text, tablename text)查询出表在各个DN占用的存储空间。 1 SELECT table_distribution(schemaname,relname) FROM get_last_changed_table();
  • 场景二:常规数据倾斜巡检 在库中表个数少于1W的场景,直接使用倾斜视图查询当前库内所有表的数据倾斜情况。 1 SELECT * FROM pgxc_get_table_skewness ORDER BY totalsize DESC; 在库中表个数非常多(至少大于1W)的场景,因PGXC_GET_TABLE_SKEWNESS涉及全库查并计算非常全面的倾斜字段,所以可能会花费比较长的时间(小时级),建议参考PGXC_GET_TABLE_SKEWNESS视图定义,直接使用table_distribution()函数自定义输出,减少输出列进行计算优化,例如: 123456 SELECT schemaname,tablename,max(dnsize) AS maxsize, min(dnsize) AS minsize FROM pg_catalog.pg_class c INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace INNER JOIN pg_catalog.table_distribution() s ON s.schemaname = n.nspname AND s.tablename = c.relname INNER JOIN pg_catalog.pgxc_class x ON c.oid = x.pcrelid AND x.pclocatortype = 'H' GROUP BY schemaname,tablename;
  • PL/pgSQL语言函数 PL/pgSQL是一种可载入的过程语言。 用PL/pgSQL创建的函数可以被用在任何可以使用内建函数的地方。例如,可以创建复杂条件的计算函数并且后面用它们来定义操作符或把它们用于索引表达式。 SQL被大多数数据库用作查询语言。它是可移植的并且容易学习。但是每一个SQL语句必须由数据库服务器单独执行。 这意味着客户端应用必须发送每一个查询到数据库服务器、等待它被处理、接收并处理结果、做一些计算,然后发送更多查询给服务器。如果客户端和数据库服务器不在同一台机器上,所有这些会引起进程间通信并且将带来网络负担。 通过PL/pgSQL,可以将一整块计算和一系列查询分组在数据库服务器内部,这样就有了一种过程语言的能力并且使SQL更易用,同时能节省的客户端/服务器通信开销。 客户端和服务器之间的额外往返通信被消除。 客户端不需要的中间结果不必被整理或者在服务器和客户端之间传送。 多轮的查询解析可以被避免。 PL/pgSQL可以使用SQL中所有的数据类型、操作符和函数。 应用PL/pgSQL创建函数的语法为CREATE FUNCTION。正如前面所说,PL/pgSQL是一种可载入的过程语言。其应用方法与存储过程相似,只是存储过程无返回值,函数有返回值。 XML类型数据支持作为自定义函数的入参,出参,自定义变量,返回值。 父主题: 用户自定义函数
  • 查看表所在节点 用户在建表时可以指定表如何在节点之间分布或者复制,详情请参考•DISTRIBUTEBY,分布方式介绍可参阅选择分布方式。 用户在建表时也可设置“Node Group”来指定表所在的Group,详情请参考•TO{GROUPgroupname|...。 用户还可以通过以下命令查看表所在实例。 查询表所在的schema。 select t1.nspname,t2.relname from pg_namespace t1,pg_class t2 where t1.oid = t2.relnamespace and t2.relname = 'table1'; 上述命令中,“nspname”为schema的名称,“relname”为表、索引、视图等对象的名称,“oid”为行标识符,“relnamespace”为包含这个关系的名称空间的OID,“table1”为表名称。 查看表的relname和nodeoids。 select t1.relname,t2.nodeoids from pg_class t1, pgxc_class t2, pg_namespace t3 where t1.relfilenode = t2.pcrelid and t1.relnamespace=t3.oid and t1.relname = 'table1' and t3.nspname ='schema1'; 上述命令中,“nodeoids”为表分布的节点OID列表,“relfilenode”为这个关系在磁盘上的文件的名称,“pcrelid”为表的OID,“schema1”为1中查询出的该表所在schema。 根据查询到的表分布的节点,查询表所在实例。 select * from pgxc_node where oid in (nodeoids1, nodeoids2, nodeoids3); 上述命令中的“nodeoids1, nodeoids2, nodeoids3”为2中查询到的3个nodeoids,操作时以实际查询到的为准,各nodeoids间以“,”隔开。 父主题: 表设计最佳实践
  • 选择分布列 Hash分布表的分布列选取至关重要,需要满足以下原则: 列值应比较离散,以便数据能够均匀分布到各个DN。例如,考虑选择表的主键为分布列,如在人员信息表中选择身份证号码为分布列。 在满足上述条件的情况下,考虑选择查询中的连接条件为分布列,以便Join任务能够下推到DN中执行,且减少DN之间的通信数据量。 对于Hash分表策略,如果分布列选择不当,可能导致数据倾斜,查询时出现部分DN的I/O短板,从而影响整体查询性能。因此在采用Hash分表策略之后需对表的数据进行数据倾斜性检查,以确保数据在各个DN上是均匀分布的。可以使用以下SQL检查数据倾斜性 12345 select xc_node_id, count(1) from tablename group by xc_node_id order by xc_node_id desc; 其中xc_node_id对应DN,一般来说,不同DN的数据量相差5%以上即可视为倾斜,如果相差10%以上就必须要调整分布列。 GaussDB支持多分布列特性,可以更好地满足数据分布的均匀性要求。 Range/List分布表的分布列由用户根据实际需要进行选择。除了需选择合适的分布列,还需要注意分布规则对数据分布的影响。 父主题: 表设计最佳实践
  • 选择数据类型 高效数据类型,主要包括以下三方面: 尽量使用执行效率比较高的数据类型 一般来说整型数据运算(包括=、>、<、≧、≦、≠等常规的比较运算,以及group by)的效率比字符串、浮点数要高。比如某客户场景中对列存表进行点查询,filter条件在一个numeric列上,执行时间为10+s;修改numeric为int类型之后,执行时间缩短为1.8s左右。 尽量使用短字段的数据类型 长度较短的数据类型不仅可以减小数据文件的大小,提升I/O性能;同时也可以减小相关计算时的内存消耗,提升计算性能。比如对于整型数据,如果可以用smallint就尽量不用int,如果可以用int就尽量不用bigint。 使用一致的数据类型 表关联列尽量使用相同的数据类型。如果表关联列数据类型不同,数据库必须动态地转化为相同的数据类型进行比较,这种转换会带来一定的性能开销。 父主题: 表设计最佳实践
  • 使用分区表 分区表是把逻辑上的一张表根据某种方案分成几张物理块进行存储。这张逻辑上的表称之为分区表,物理块称之为分区。分区表是一张逻辑表,不存储数据,数据实际是存储在分区上的。分区表和普通表相比具有以下优点: 改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索效率。 增强可用性:如果分区表的某个分区出现故障,表在其他分区的数据仍然可用。 方便维护:如果分区表的某个分区出现故障,需要修复数据,只修复该分区即可。 GaussDB支持的分区表为范围分区表,列表分区表,哈希分区表。 范围分区表:将数据基于范围映射到每一个分区。这个范围是由创建分区表时指定的分区键决定的。分区键经常采用日期,例如将销售数据按照月份进行分区。 列表分区表:将数据中包含的键值分别存储在不同的分区中,依次将数据映射到每一个分区,分区中包含的键值由创建分区表时指定。 哈希分区表:将数据根据内部哈希算法依次映射到每一个分区中,包含的分区个数由创建分区表时指定 父主题: 表设计最佳实践
  • 选择分布方式 复制表(Replication)方式将表中的全量数据在集群的每一个DN实例上保留一份。主要适用于记录集较小的表。这种存储方式的优点是每个DN上都有该表的全量数据,在join操作中可以避免数据重分布操作,从而减小网络开销,同时减少了plan segment(每个plan segment都会起对应的线程);缺点是每个DN都保留了表的完整数据,造成数据的冗余。一般情况下只有较小的维度表才会定义为Replication表。 哈希(Hash)表将表中某一个或几个字段进行hash运算后,生成对应的hash值,根据DN实例与哈希值的映射关系获得该元组的目标存储位置。对于Hash分布表,在读/写数据时可以利用各个节点的I/O资源,大大提升表的读/写速度。一般情况下大表定义为Hash表。 范围(Range)和列表(List)分布是由用户自定义的分布策略,根据分布列的取值落入满足一定范围或者具体值的对应目标DN,这两种分布方式便于用户灵活地进行数据管理,但对用户本身的数据抽象能力有一定的要求。 策略 描述 适用场景 Hash 表数据通过hash方式散列到集群中的所有DN实例上。 数据量较大的事实表。 Replication 集群中每一个DN实例上都有一份全量表数据。 小表、维度表。 Range 表数据对指定列按照范围进行映射,分布到对应DN。 用户需要自定义分布规则的场景。 List 表数据对指定列按照具体值进行映射,分布到对应DN。 用户需要自定义分布规则的场景。 如图1所示,复制表如图中的表T1,哈希表如图中的表T2。 图1 复制表和哈希表 父主题: 表设计最佳实践
  • 参数说明 WITH [ RECURSIVE ] with_query [, ...] 用于声明一个或多个可以在主查询中通过名称引用的子查询,相当于临时表。 如果声明了RECURSIVE,那么允许SELECT子查询通过名称引用它自己。 其中with_query的详细格式为:with_query_name [ ( column_name [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( {select | values | insert | update | delete} ) with_query_name指定子查询生成的结果集名称,在查询中可使用该名称访问子查询的结果集。 column_name指定子查询结果集中显示的列名。 每个子查询可以是SELECT,VALUES,INSERT,UPDATE或DELETE语句。 用户可以使用MATERIALIZED / NOT MATERIALIZED对CTE进行修饰。 如果声明为MATERIALIZED,WITH查询将被物化,生成一个子查询结果集的拷贝,在引用处直接查询该拷贝,因此WITH子查询无法和主干SELECT语句进行联合优化(如谓词下推、等价类传递等),对于此类场景可以使用NOT MATERIALIZED进行修饰,如果WITH查询语义上可以作为子查询内联执行,则可以进行上述优化。 如果用户没有显示声明物化属性则遵守以下规则:如果CTE只在所属SELECT主干中被引用一次,且语义上支持内联执行,则会被改写为子查询内联执行,否则以CTE Scan的方式物化执行。 plan_hint子句 以/*+ */的形式在UPDATE关键字后,用于对UPDATE对应的语句块生成的计划进行hint调优,详细用法请参见章节使用Plan Hint进行调优。每条语句中只有第一个/*+ plan_hint */注释块会作为hint生效,里面可以写多条hint。 table_name 要更新的表名,可以使用模式修饰。 取值范围:已存在的表名称。 alias 目标表的别名。 取值范围:字符串,符合标识符命名规范。 column_name 要修改的字段名。 支持使用目标表的别名加字段名来引用这个字段。例如: UPDATE foo AS f SET f.col_name = namecol'; 取值范围:已存在的字段名。 expression 赋给字段的值或表达式。 DEFAULT 用对应字段的缺省值填充该字段。 如果没有缺省值,则为NULL。 sub_query 子查询。 使用同一数据库里其他表的信息来更新一个表可以使用子查询的方法。其中SELECT子句具体介绍请参考SELECT。 在update单列时,支持使用order by子句与limit子句;而在update多列时,则不支持使用order by子句与limit子句。 from_list 一个表的表达式列表,允许在WHERE条件里使用其他表的字段。与在一个SELECT语句的FROM子句里声明表列表类似。 目标表不能出现在from_list里,除非在使用一个自连接(此时它必须以from_list的别名出现)。 condition 一个返回Boolean类型结果的表达式。只有这个表达式返回true的行才会被更新。不建议使用int等数值类型作为condition,因为int等数值类型可以隐式转换为bool值(非0值隐式转换为true,0转换为false),可能导致非预期的结果。 WHERE CURRENT OF cursor_name 当cursor指向表的某一行时,可以使用此语法更新cursor当前指向的行。 cursor_name:指定游标的名称。 MYSQL兼容模式的数据库不支持使用此语法。 此语法仅支持普通表,不支持分区表,不支持列存,不支持Hash Bucket表。 仅支持在存储过程中使用。 不支持与其他WHERE条件组合使用。 不支持与WITH、USING、ORDER BY、FROM组合使用。 cursor对应的SELECT语句必须声明为FOR UPDATE。 cursor对应的SELECT语句仅支持单表,不支持LIMIT/OFFSET,不支持带有子查询、子链接。 存储过程中声明为FOR UPDATE的cursor,在commit/rollback后,将无法再次使用。 若cursor指向的行已经不存在,在ORA兼容性模式下将报错指定的行不存在(仅UPDATE时报错,DELETE不报错),其他兼容模式下不报错。 ORDER BY子句 关键字详见SELECT章节介绍。 LIMIT子句 关键字详见SELECT章节介绍。 output_expression 在所有需要更新的行都被更新之后,UPDATE命令用于计算返回值的表达式。 取值范围:使用任何table以及FROM中列出的表的字段。*表示返回所有字段。 output_name 字段的返回名称。
  • 示例 1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233343536373839404142 --创建表student1。gaussdb=# CREATE TABLE student1( stuno int, classno int )DISTRIBUTE BY hash(stuno);--插入数据。gaussdb=# INSERT INTO student1 VALUES(1,1);gaussdb=# INSERT INTO student1 VALUES(2,2);gaussdb=# INSERT INTO student1 VALUES(3,3);--查看数据。gaussdb=# SELECT * FROM student1;--直接更新所有记录的值。gaussdb=# UPDATE student1 SET classno = classno*2;--查看数据。gaussdb=# SELECT * FROM student1;--删除表。gaussdb=# DROP TABLE student1;--WHERE CURRENT OF cursor_name用例gaussdb=# create table t1(c1 int, c2 varchar2); -- 创建表gaussdb=# insert into t1 values(generate_series(1,1000),'abcd'); -- 插入数据gaussdb=# declaregaussdb-# cursor cur1 is select * from t1 where c1 = 1 for update;gaussdb-# va t1%rowtype;gaussdb-# begingaussdb$# open cur1;gaussdb$# fetch cur1 into va;gaussdb$# update t1 set c2 = c2 || c2 where current of cur1; -- 使用WHERE CURRENT OF cursor_name更新数据gaussdb$# close cur1;gaussdb$# commit;gaussdb$# end;gaussdb$# /gaussdb=# select * from t1 where c1 = 1; -- 查询数据
  • 注意事项 表的所有者、拥有表UPDATE权限的用户或拥有UPDATE ANY TABLE权限的用户,有权更新表中的数据,系统管理员默认拥有此权限。 Update...... Limit row_count 仅支持执行计划下推的部分场景(不支持复制表),前置条件是过滤条件需要包含等值分布列,且过滤条件相对简单,避免使用强制类型转换。如果执行失败,请简化过滤条件。 对expression或condition条件里涉及到的任何表要有SELECT权限。 不允许对表的分布列(distribute column)进行修改。 对于列存表,暂时不支持RETURNING子句。 列存表不支持结果不确定的更新(non-deterministic update)。试图对列存表用多行数据更新一行时会报错。 列存表的更新操作,旧记录空间不会回收,需要执行VACUUM FULL table_name进行清理。 对于列存复制表,暂不支持UPDATE操作。 对于子查询是stream计划的UPDATE语句,不支持并发更新同一行。
  • 语法格式 1 2 3 4 5 6 7 8 9101112131415161718 [ WITH [ RECURSIVE ] with_query [, ...] ]UPDATE [/*+ plan_hint */] [ ONLY ] table_name [ * ] [ [ AS ] alias ]SET {column_name = { expression | DEFAULT } |( column_name [, ...] ) = {( { expression | DEFAULT } [, ...] ) |sub_query }}[, ...] [ FROM from_list] [ WHERE condition | WHERE CURRENT OF cursor_name ] [ ORDER BY {expression [ [ ASC | DESC | USING operator ] [ LIMIT row_count ] [ RETURNING {* | {output_expression [ [ AS ] output_name ]} [, ...] }];where sub_query can be:SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]{ * | {expression [ [ AS ] output_name ]} [, ...] }[ FROM from_item [, ...] ][ WHERE condition | WHERE CURRENT OF cursor_name ][ GROUP BY grouping_element [, ...] ][ HAVING condition [, ...] ][ ORDER BY {expression [ [ ASC | DESC | USING operator ] | nlssort_expression_clause ] [ NULLS { FIRST | LAST } ]} [, ...] ][ LIMIT { [offset,] count | ALL } ]
  • 选择存储模型 进行数据库设计时,表设计上的一些关键项将严重影响后续整库的查询性能。表设计对数据存储也有影响:好的表设计能够减少I/O操作及最小化内存使用,进而提升查询性能。 表的存储模型选择是表定义的第一步。客户业务属性是表的存储模型的决定性因素,依据下面表格选择适合当前业务的存储模型。 存储模型 适用场景 行存 点查询(返回记录少,基于索引的简单查询)。 增删改比较多的场景。 列存 统计分析类查询 (group , join多的场景)。 父主题: 表设计最佳实践
  • 扩展函数 下表列举了GaussDB中支持的扩展函数,不作为商用特性交付,仅供参考。 分类 函数名称 描述 触发器函数 pg_get_triggerdef(trigger_oid) 为触发器获取CREATE [ CONSTRAINT ] TRIGGER命令 pg_get_triggerdef(trigger_oid, pretty_bool) 为触发器获取CREATE [ CONSTRAINT ] TRIGGER命令 父主题: 附录
  • 优化建议 vacuum VACUUM不能在事务块内执行。 建议生产数据库经常清理(至少每晚一次),以保证不断地删除失效的行。尤其是在增删了大量记录后,对相关表执行VACUUM ANALYZE命令。 不建议日常使用FULL选项,但是可以在特殊情况下使用。例如,一个例子就是在用户删除了一个表的大部分行之后,希望从物理上缩小该表以减少磁盘空间占用。 执行VACUUM FULL操作时,建议首先删除相关表上的所有索引,再运行VACUUM FULL命令,最后重建索引。
  • 示例 123456789 --在表tpcds.reason上创建索引CREATE UNIQUE INDEX ds_reason_index1 ON tpcds.reason(r_reason_sk);--对带索引的表tpcds.reason执行VACUUM操作。gaussdb=# VACUUM (VERBOSE, ANALYZE) tpcds.reason;--删除索引gaussdb=# DROP INDEX ds_reason_index1 CASCADE;gaussdb=# DROP TABLE tpcds.reason;
  • 注意事项 如果没有参数,VACUUM处理当前数据库里用户拥有相应权限的每个表。如果参数指定了一个表,VACUUM只处理指定的那个表。 要对一个表进行VACUUM操作,通常用户必须是表的所有者或者被授予了指定表VACUUM权限的用户,默认系统管理员有该权限。数据库的所有者允许对数据库中除了共享目录以外的所有表进行VACUUM操作(该限制意味着只有系统管理员才能真正对一个数据库进行VACUUM操作)。VACUUM命令会跳过那些用户没有权限的表进行垃圾回收操作。 VACUUM不能在事务块内执行。 建议生产数据库经常清理(至少每晚一次),以保证不断地删除失效的行。尤其是在增删了大量记录之后,对受影响的表执行VACUUM ANALYZE命令是一个很好的习惯。这样将更新系统目录为最近的更改,并且允许查询优化器在规划用户查询时有更好的选择。 不建议日常使用FULL选项,但是可以在特殊情况下使用。例如在用户删除了一个表的大部分行之后,希望从物理上缩小该表以减少磁盘空间占用。VACUUM FULL通常要比单纯的VACUUM收缩更多的表尺寸。FULL选项并不清理索引,所以推荐周期性的运行REINDEX命令。实际上,首先删除所有索引,再运行VACUUM FULL命令,最后重建索引通常是更快的选择。如果执行此命令后所占用物理空间无变化(未减少),请确认是否有其他活跃事务(删除数据事务开始之前开始的事务,并在VACUUM FULL执行前未结束)存在,如果有等其他活跃事务退出进行重试。 VACUUM会导致I/O流量的大幅增加,这可能会影响其他活动会话的性能。因此,有时候会建议使用基于开销的VACUUM延迟特性。 如果指定了VERBOSE选项,VACUUM将打印处理过程中的信息,以表明当前正在处理的表。各种有关当前表的统计信息也会打印出来。但是对于列存表执行VACUUM操作,指定了VERBOSE选项,无信息输出。 当含有带括号的选项列表时,选项可以以任何顺序写入。如果没有括号,则选项必须按语法显示的顺序给出。 VACUUM和VACUUM FULL时,会根据参数vacuum_defer_cleanup_age延迟清理行存表记录,即不会立即清理刚刚删除的元组。 VACUUM ANALYZE先执行一个VACUUM操作,然后给每个选定的表执行一个ANALYZE。对于日常维护脚本而言,这是一个很方便的组合。 简单的VACUUM(不带FULL选项)只是简单地回收空间并且令其可以再次使用。这种形式的命令可以和对表的普通读写并发操作,因为没有请求排他锁。VACUUM FULL执行更广泛的处理,包括跨块移动行,以便把表压缩到最少的磁盘块数目里。这种形式要慢许多并且在处理的时候需要在表上施加一个排他锁。 VACUUM列存表内部执行的操作包括三个:迁移delta表中的数据到主表、VACUUM主表的delta表、VACUUM主表的desc表。该操作不会回收delta表的存储空间,如果要回收delta表的冗余存储空间,需要对该列存表执行VACUUM DELTAMERGE。 时序表(当前特性是实验室特性,使用时请联系华为工程师提供技术支持)VACUUM FULL和时序Compaction功能一致,故时序Compaction功能关闭时才可执行VACUUM FULL命令。 如果没有打开xc_maintenance_mode参数,那么VACUUM FULL会跳过所有系统表。 执行DELETE后立即执行VACUUM FULL命令不会回收空间。执行DELETE后再执行1000个非SELECT事务,或者等待1s后再执行1个事务,之后再执行VACUUM FULL命令空间才会回收。 VACUUM FULL期间会对表加排他锁,不建议在业务高峰期运行VACUUM FULL,否则会导致等锁时间过长或者死锁。 为保证性能和统计信息的准确性,避免vacuum analyze、autoanalyze、手动analyze等涉及analyze的命令同时执行或执行过于频繁。
  • 语法格式 回收空间并更新统计信息,对关键字顺序无要求。 12 VACUUM [ ( { FULL | FREEZE | VERBOSE | {ANALYZE | ANALYSE }} [,...] ) ] [ table_name [ (column_name [, ...] ) ] [ PARTITION ( partition_name ) ] ]; 仅回收空间,不更新统计信息。 1 VACUUM [ FULL [COMPACT] ] [ FREEZE ] [ VERBOSE ] [ table_name [ PARTITION ( partition_name ) ] ]; 回收空间并更新统计信息,且对关键字顺序有要求。 12 VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] { ANALYZE | ANALYSE } [ VERBOSE ] [ table_name [ (column_name [, ...] ) ] [ PARTITION ( partition_name ) ] ];
  • 参数说明 FULL 选择“FULL”清理,这样可以恢复更多的空间,但是需要耗时更多,并且在表上施加了排他锁。 使用FULL参数会导致统计信息丢失,如果需要收集统计信息,请在VACUUM FULL语句中加上analyze关键字。 FREEZE 指定FREEZE相当于执行VACUUM时将vacuum_freeze_min_age参数设为0。 VERBOSE 为每个表打印一份详细的清理工作报告。 ANALYZE | ANALYSE 更新用于优化器的统计信息,以决定执行查询的最有效方法。 table_name 要清理的表的名称(可以有模式修饰)。 取值范围:要清理的表的名称。缺省时为当前数据库中的所有表。 column_name 要分析的具体的字段名称,需要配合analyze选项使用。 取值范围:要分析的具体的字段名称。缺省时为所有字段。 PARTITION COMPACT和PARTITION参数不能同时使用。 partition_name 要清理的表的分区名称。缺省时为所有分区。 DELTAMERGE 只针对列存表,将列存表的delta table中的数据转移到主表存储上。对列存表而言,此操作受GUC参数enable_delta_store和参数说明中的deltarow_threshold控制。 为了检查列存delta表中的信息,提供下述DFX函数,用于获取某个列存表的delta表中数据存储情况: pgxc_get_delta_info(TEXT),传入参数为列存表名,搜集并显示各个节点上的对应delta表信息,包括当前存活tuple数量、表大小、使用的最大block ID。 get_delta_info(TEXT),传入参数为列存表名,汇总pgxc_get_delta_info得到的结果,返回其delta表整体的当前存活tuple数量、表大小、使用的最大block ID。
  • 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索引
共100000条