华为云用户手册

  • 示例 显示用字母t和f输出Boolean值。 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 --创建表。 gaussdb=# CREATE TABLE bool_type_t1 ( BT_COL1 BOOLEAN, BT_COL2 TEXT )DISTRIBUTE BY HASH(BT_COL2); --插入数据。 gaussdb=# INSERT INTO bool_type_t1 VALUES (TRUE, 'sic est'); gaussdb=# INSERT INTO bool_type_t1 VALUES (FALSE, 'non est'); --查看数据。 gaussdb=# SELECT * FROM bool_type_t1; bt_col1 | bt_col2 ---------+--------- t | sic est f | non est (2 rows) gaussdb=# SELECT * FROM bool_type_t1 WHERE bt_col1 = 't'; bt_col1 | bt_col2 ---------+--------- t | sic est (1 row) --删除表。 gaussdb=# DROP TABLE bool_type_t1;
  • 货币类型 货币类型存储带有固定小数精度的货币金额。 表1中显示的范围假设有两位小数。可以以任意格式输入,包括整型、浮点型或者典型的货币格式(如“$1,000.00”)。根据区域字符集,输出一般是最后一种形式。 表1 货币类型 名称 描述 存储容量 范围 money 货币金额 8 字节 -92233720368547758.08 ~ +92233720368547758.07 numeric,int和bigint类型的值可以转换为money类型。如果从real和double precision类型转换到money类型,可以先转换为numeric类型,再转换为money类型,例如: 1 2 3 4 5 gaussdb=# SELECT '12.34'::float8::numeric::money; money -------- $12.34 (1 row) 这种用法是不推荐使用的。浮点数不应该用来处理货币类型,因为小数点的位数可能会导致错误。 money类型的值可以转换为numeric类型而不丢失精度。转换为其他类型可能丢失精度,并且必须通过以下两步来完成: 1 2 3 4 5 gaussdb=# SELECT '52093.89'::money::numeric::float8; float8 ---------- 52093.89 (1 row) 当一个money类型的值除以另一个money类型的值时,结果是double precision(即一个纯数字,而不是money类型);在运算过程中货币单位相互抵消。 父主题: 数据类型
  • 数值类型 表1列出了所有的可用类型。数字操作符和相关的内置函数请参见数字操作函数和操作符。 表1 整数类型 名称 描述 存储空间 范围 TINYINT 微整数,别名为INT1。 1字节 0 ~ +255 SMALLINT 小范围整数,别名为INT2。 2字节 -32,768 ~ +32,767 INTEGER 常用的整数,别名为INT4。 4字节 -2,147,483,648 ~ +2,147,483,647 BINARY_INTEGER 常用的整数INTEGER的别名。 4字节 -2,147,483,648 ~ +2,147,483,647 BIGINT 大范围的整数,别名为INT8。 8字节 -9,223,372,036,854,775,808 ~ +9,223,372,036,854,775,807 int16 十六字节的大范围整数,目前不支持用户用于建表等使用。 16字节 -170,141,183,460,469,231,731,687,303,715,884,105,728 ~ +170,141,183,460,469,231,731,687,303,715,884,105,727 示例: --创建具有TINYINT类型数据的表。 gaussdb=# CREATE TABLE int_type_t1 ( IT_COL1 TINYINT ); --插入数据。 gaussdb=# INSERT INTO int_type_t1 VALUES(10); --查看数据。 gaussdb=# SELECT * FROM int_type_t1; it_col1 --------- 10 (1 row) --删除表。 gaussdb=# DROP TABLE int_type_t1; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 --创建具有TINYINT,INTEGER,BIGINT类型数据的表。 gaussdb=# CREATE TABLE int_type_t2 ( a TINYINT, b TINYINT, c INTEGER, d BIGINT ); --插入数据。 gaussdb=# INSERT INTO int_type_t2 VALUES(100, 10, 1000, 10000); --查看数据。 gaussdb=# SELECT * FROM int_type_t2; a | b | c | d -----+----+------+------- 100 | 10 | 1000 | 10000 (1 row) --删除表。 gaussdb=# DROP TABLE int_type_t2; TINYINT、SMALLINT、INTEGER、BIGINT和INT16类型存储各种范围的数字,即整数。如果存储超出范围以外的数值将会导致错误。 常用的类型是INTEGER,因为它提供了在范围、存储空间、性能之间的最佳平衡。一般只有取值范围确定不超过SMALLINT的情况下,才会使用SMALLINT类型。而只有在INTEGER的范围不够的时候才使用BIGINT,因为INTEGER的处理速度相对快得多。 表2 任意精度类型 名称 描述 存储空间 范围 NUMERIC[(p[,s])], DECIMAL[(p[,s])] 精度p取值范围为[1,1000],标度s取值范围为[0,p]。 说明: p为总位数,s为小数位数。 用户声明精度。每四位(十进制位)占用两个字节,然后在整个数据上加上八个字节的额外开销。 未指定精度的情况下,小数点前最大131,072位,小数点后最大16,383位。 NUMBER[(p[,s])] NUMERIC类型的别名。 用户声明精度。每四位(十进制位)占用两个字节,然后在整个数据上加上八个字节的额外开销。 未指定精度的情况下,小数点前最大131,072位,小数点后最大16,383位。 示例: --创建表。 gaussdb=# CREATE TABLE decimal_type_t1 ( DT_COL1 DECIMAL(10,4) ); --插入数据。 gaussdb=# INSERT INTO decimal_type_t1 VALUES(123456.122331); --查询表中的数据。 gaussdb=# SELECT * FROM decimal_type_t1; dt_col1 ------------- 123456.1223 (1 row) --删除表。 gaussdb=# DROP TABLE decimal_type_t1; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 --创建表。 gaussdb=# CREATE TABLE numeric_type_t1 ( NT_COL1 NUMERIC(10,4) ); --插入数据。 gaussdb=# INSERT INTO numeric_type_t1 VALUES(123456.12354); --查询表中的数据。 gaussdb=# SELECT * FROM numeric_type_t1; nt_col1 ------------- 123456.1235 (1 row) --删除表。 gaussdb=# DROP TABLE numeric_type_t1; 与整数类型相比,任意精度类型需要更大的存储空间,其存储效率、运算效率以及压缩比效果都要差一些。在进行数值类型定义时,优先选择整数类型。当数值超出整数可表示最大范围时,再选用任意精度类型。 使用NUMERIC/DECIMAL进行列定义时,建议指定该列的精度p以及标度s。 表3 序列整型 名称 描述 存储空间 范围 SMALLSERIAL 二字节序列整型。 2字节。 -32,768 ~ +32,767。 SERIAL 四字节序列整型。 4字节。 -2,147,483,648 ~ +2,147,483,647。 BIGSERIAL 八字节序列整型。 8字节。 -9,223,372,036,854,775,808 ~ +9,223,372,036,854,775,807。 示例: 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 --创建表。 gaussdb=# CREATE TABLE smallserial_type_tab(a SMALLSERIAL); --插入数据。 gaussdb=# INSERT INTO smallserial_type_tab VALUES(default); --再次插入数据。 gaussdb=# INSERT INTO smallserial_type_tab VALUES(default); --查看数据。 gaussdb=# SELECT * FROM smallserial_type_tab; a --- 1 2 (2 rows) --创建表。 gaussdb=# CREATE TABLE serial_type_tab(b SERIAL); --插入数据。 gaussdb=# INSERT INTO serial_type_tab VALUES(default); --再次插入数据。 gaussdb=# INSERT INTO serial_type_tab VALUES(default); --查看数据。 gaussdb=# SELECT * FROM serial_type_tab; b --- 1 2 (2 rows) --创建表。 gaussdb=# CREATE TABLE bigserial_type_tab(c BIGSERIAL); --插入数据。 gaussdb=# INSERT INTO bigserial_type_tab VALUES(default); --再次插入数据。 gaussdb=# INSERT INTO bigserial_type_tab VALUES(default); --查看数据。 gaussdb=# SELECT * FROM bigserial_type_tab; c --- 1 2 (2 rows) --删除表。 gaussdb=# DROP TABLE smallserial_type_tab; gaussdb=# DROP TABLE serial_type_tab; gaussdb=# DROP TABLE bigserial_type_tab; SMALLSERIAL、SERIAL和BIGSERIAL类型不是真正的类型,只是为在表中设置唯一标识做的概念上的便利。因此,创建一个整数字段,并且把它的缺省数值安排为从一个序列发生器读取。应用了一个NOT NULL约束以确保NULL不会被插入。在大多数情况下用户可能还希望附加一个UNIQUE或PRIMARY KEY约束避免意外地插入重复的数值,但这个不是自动的。最后,序列发生器将从属于该字段,这样当该字段或表被删除的时候也一并删除它。目前只支持在创建表时候指定SERIAL列,不可以在已有的表中,增加SERIAL列。另外临时表也不支持创建SERIAL列。因为SERIAL不是真正的类型,所以也不可以将表中存在的列类型转化为SERIAL。 表4 浮点类型 名称 描述 存储空间 范围 REAL, FLOAT4 单精度浮点数,不精准。 4字节。 -3.402E+38~+3.402E+38,6位十进制数字精度。 DOUBLE PRECISION, FLOAT8 双精度浮点数,不精准。 8字节。 -1.79E+308~+1.79E+308,15位十进制数字精度。 FLOAT[(p)] 浮点数,不精准。精度p取值范围为[1,53]。 说明: p为精度,表示二进制总位数。 4字节或8字节。 根据精度p不同选择REAL或DOUBLE PRECISION作为内部表示。如不指定精度,内部用DOUBLE PRECISION表示。 BINARY_DOUBLE 是DOUBLE PRECISION的别名,为兼容Oracle数据类型。 8字节。 -1.79E+308~+1.79E+308,15位十进制数字精度。 DEC[(p[,s])] 精度p取值范围为[1,1000],标度s取值范围为[0,p]。 说明: p为总位数,s为小数位位数。 用户声明精度。每四位(十进制位)占用两个字节,然后在整个数据上加上八个字节的额外开销。 在精度和标度指定最大的情况下,小数点前最大131,072位,小数点后最大16,383位。 INTEGER[(p[,s])] 精度p取值范围为[1,1000],标度s取值范围为[0,p]。 在未指定精度和标度的情况下,默认精度p为10,标度s为0。 未指定精度和标度的情况下,该类型映射为INTEGER。指定精度和标度的情况下,该类型映射为NUMERIC。 用户声明精度。每四位(十进制位)占用两个字节,然后在整个数据上加上八个字节的额外开销。 在精度和标度指定最大的情况下,小数点前最大131,072位,小数点后最大16,383位。 未指定精度和标度的情况下,范围是-2,147,483,648 ~ +2,147,483,647。 关于浮点类型的精度,目前只能保证直接读取时的精度位数。涉及分布式计算时,由于计算执行在各个DN节点上,并且最终汇聚到一个CN节点,因此误差可能会随计算节点数量增加而被放大。 表4中描述的p为精度,表示整数位最低可以接受的总位数;s为小数位位数。 示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 --创建表。 gaussdb=# CREATE TABLE float_type_t2 ( FT_COL1 INTEGER, FT_COL2 FLOAT4, FT_COL3 FLOAT8, FT_COL4 FLOAT(3), FT_COL5 BINARY_DOUBLE, FT_COL6 DECIMAL(10,4), FT_COL7 INTEGER(6,3) )DISTRIBUTE BY HASH ( ft_col1); --插入数据。 gaussdb=# INSERT INTO float_type_t2 VALUES(10,10.365456,123456.1234,10.3214, 321.321, 123.123654, 123.123654); --查看数据。 gaussdb=# SELECT * FROM float_type_t2 ; ft_col1 | ft_col2 | ft_col3 | ft_col4 | ft_col5 | ft_col6 | ft_col7 ---------+---------+-------------+---------+---------+----------+--------- 10 | 10.3655 | 123456.1234 | 10.3214 | 321.321 | 123.1237 | 123.124 (1 row) --删除表。 gaussdb=# DROP TABLE float_type_t2; 父主题: 数据类型
  • 数据类型 数据类型是数据的一个基本属性,用于区分不同类型的数据。不同的数据类型所占的存储空间不同,能够进行的操作也不相同。数据库中的数据存储在数据表中。数据表中的每一列都定义了数据类型,用户存储数据时,须遵从这些数据类型的属性,否则可能会出错。 GaussDB 支持某些数据类型间的隐式转换,具体转换关系请参见PG_CAST。 数值类型 货币类型 布尔类型 字符类型 二进制类型 日期/时间类型 几何类型 网络地址类型 位串类型 UUID类型 JSON/JSONB类型 HLL数据类型 范围类型 对象标识符类型 伪类型 XML类型 XMLTYPE类型 aclitem类型 数组类型 父主题: SQL参考
  • 什么是SQL SQL是用于访问和处理数据库的标准计算机语言。 SQL提供了各种任务的语句,包括: 查询数据。 在表中插入、更新和删除行。 创建、替换、更改和删除对象。 控制对数据库及其对象的访问。 保证数据库的一致性和完整性。 SQL语言由用于处理数据库和数据库对象的命令和函数组成。该语言还会强制实施有关数据类型、表达式和文本使用的规则。因此在SQL参考章节,除了SQL语法参考外,还介绍了有关数据类型、表达式、函数和操作符等信息。
  • SQL发展简史 SQL发展简史如下: 1986年,ANSI X3.135-1986,ISO/IEC 9075:1986,SQL-86 1989年,ANSI X3.135-1989,ISO/IEC 9075:1989,SQL-89 1992年,ANSI X3.135-1992,ISO/IEC 9075:1992,SQL-92(SQL2) 1999年,ISO/IEC 9075:1999,SQL:1999(SQL3) 2003年,ISO/IEC 9075:2003,SQL:2003(SQL4) 2011年,ISO/IEC 9075:200N,SQL:2011(SQL5)
  • 案例环境准备 为了便于案例演示,需准备建表语句如下: --清理环境 DROP SCHEMA IF EXISTS dn_gather_test CASCADE; CREATE SCHEMA dn_gather_test; SET current_schema=dn_gather_test; --创建测试表 CREATE TABLE t1(a INT, b INT, c INT, d INT); CREATE TABLE t2(a INT, b INT, c INT, d INT); CREATE TABLE t3(a INT, b INT, c INT, d INT); CREATE TABLE t4(a INT, b INT, c INT, d INT);
  • 案例环境准备 为了便于规则的使用场景演示,需准备建表语句如下: --清理环境 DROP SCHEMA IF EXISTS rewrite_rule_guc_test CASCADE; CREATE SCHEMA rewrite_rule_guc_test; SET current_schema=rewrite_rule_guc_test; --创建测试表 CREATE TABLE t(c1 INT, c2 INT, c3 INT, c4 INT); CREATE TABLE t1(c1 INT, c2 INT, c3 INT, c4 INT); CREATE TABLE t2(c1 INT, c2 INT, c3 INT, c4 INT);
  • 现象描述 in-clause/any-clause是常见的SQL语句约束条件,有时in或any后面的clause都是常量,类似于: 1 select count(1) from calc_empfyc_c1_result_tmp_t1 where ls_pid_cusr1 in (‘20120405’, ‘20130405’); 或者 1 select count(1) from calc_empfyc_c1_result_tmp_t1 where ls_pid_cusr1 in any(‘20120405’, ‘20130405’); 但是也有一些如下的特殊用法: 1 SELECT ls_pid_cusr1,COALESCE(max(round((current_date-bthdate)/365)),0)FROM calc_empfyc_c1_result_tmp_t1 t1,p10_md_tmp_t2 t2WHERE t1.ls_pid_cusr1 = any(values(id),(id15))GROUP BY ls_pid_cusr1; 其中,id、id15为p10_md_tmp_t2中的两列,“t1.ls_pid_cusr1 = any(values(id),(id15))”等价于“t1.ls_pid_cusr1 = id or t1.ls_pid_cusr1 = id15”。 因此join-condition实质上是一个不等式,这种非等值的join操作必须使用nestloop连接,对应执行计划如下:
  • 优化说明 测试发现由于两表结果集过大,导致nestloop耗时过长,超过一小时未返回结果,因此性能优化的关键是消除nestloop,让join使用更高效的hashjoin。从语义等价的角度消除any-clause,SQL改写如下: 1 selectls_pid_cusr1,COALESCE(max(round(ym/365)),0)from( ( SELECT ls_pid_cusr1,(current_date-bthdate) as ym FROM calc_empfyc_c1_result_tmp_t1 t1,p10_md_tmp_t2 t2 WHERE t1.ls_pid_cusr1 = t2.id and t1.ls_pid_cusr1 != t2.id15 ) union all ( SELECT ls_pid_cusr1,(current_date-bthdate) as ym FROM calc_empfyc_c1_result_tmp_t1 t1,p10_md_tmp_t2 t2 WHERE t1.ls_pid_cusr1 = id15 ))GROUP BY ls_pid_cusr1; 优化后的SQL查询由两个等值join的子查询构成,而每个子查询都可以走更适合此场景的hashjoin。优化后的执行计划如下 优化后,从超过1个小时未返回结果优化到7s返回结果。
  • 现象描述 某局点测试中:ddw_f10_op_cust_asset_mon为分区表,分区键为year_mth,此字段是由年月两个值拼接而成的字符串。 测试SQL如下: 1 select count(1) from t_ddw_f10_op_cust_asset_mon b1where b1.year_mth between to_char(add_months(to_date(''20170222'','yyyymmdd'), -11),'yyyymm') and substr(''20170222'',1 ,6 ); 测试结果显示此SQL的表Scan耗时长达135s。初步猜测可能是性能瓶颈点。 add_months为本地适配函数: 1 CREATE OR REPLACE FUNCTION ADD_MONTHS(date, integer) RETURNS date AS $$ SELECT CASE WHEN (EXTRACT(day FROM $1) = EXTRACT(day FROM (date_trunc('month', $1) + INTERVAL '1 month - 1 day'))) THEN date_trunc('month', $1) + CAST($2 + 1 || ' month - 1 day' as interval) ELSE $1 + CAST($2 || ' month' as interval) END $$ LANGUAGE SQL IMMUTABLE;
  • 优化说明 此优化的核心就是消除子查询。分析业务场景发现a.ca_address_sk不为null,那么从SQL语义出发,可以等价改写SQL为: 1 2 3 4 5 select count(*) from customer_address_001 a4, customer_address_001 a where a4.ca_address_sk = a.ca_address_sk group by a.ca_address_sk; 为了保证改写的等效性,在customer_address_001. ca_address_sk加了not null约束。
  • 优化说明 通常优化器总会选择最优的执行计划,但是众所周知代价估算,尤其是中间结果集的代价估算一般会有比较大的偏差,这种比较大的偏差就可能会导致agg的计算方式出现比较大的偏差,这时候就需要通过best_agg_plan进行agg计算模型的干预。 一般来说,当agg汇聚的收敛度很小时,即结果集的个数在agg之后并没有明显变少时(经验上以5倍为临界点),选择redistribute+hashagg执行方式,否则选择hashagg+redistribute+hashagg执行方式。
  • 现象描述 某局点测试过程中EXPLAIN ANALYZE后有如下情况: 从执行信息上比较明确的可以看出HashJoin是整个计划的性能瓶颈点,并且从HashJoin的执行时间信息[2657.406,93339.924](数值的具体含义请参见SQL执行计划详解),上可以看出HashJoin在不同的DN上存在严重的计算偏斜。 同时在Memory Information(如下图)中可以看出各个节点的内存资源消耗也存在极为严重的偏斜。
  • 优化分析 上述两个特征表明了此SQL语句存在极为严重的计算倾斜。进一步向HashJoin算子的下层分析发现Seq Scan on s_riskrate_setting也存在极为严重的计算倾斜[38.885,2940.983]。根据Scan的含义推测此计划性能问题的根源在于表s_riskrate_setting数据的分布倾斜。实际分析之后确实发现表s_riskrate_setting存在严重的数据倾斜。整改之后性能从94s提升为50s。
  • 优化分析 如果将a作为t1和t2的分布列: 1 2 CREATE TABLE t1 (a int, b int) DISTRIBUTE BY HASH (a); CREATE TABLE t2 (a int, b int) DISTRIBUTE BY HASH (a); 则执行计划将存在“Streaming”,导致DN之间存在较大通信数据量,如图1所示。 图1 选择合适的分布列案例(一) 如果将a作为t1的分布列,将b作为t2的分布列: 1 2 CREATE TABLE t1 (a int, b int) DISTRIBUTE BY HASH (a); CREATE TABLE t2 (a int, b int) DISTRIBUTE BY HASH (b); 则执行计划将不包含“Streaming”,减少DN之间存在的通信数据量,从而提升查询性能,如图2所示。 图2 选择合适的分布列案例(二)
  • 相关链接 SQL PATCH相关系统函数、系统表、系统视图和接口函数见下表。 表1 SQL PATCH相关系统函数、系统表、系统视图和接口函数介绍 类别 名称 说明 系统函数 global_sql_patch_func() 全局各个节点上的SQL PATCH信息,用于返回global_sql_patch视图的结果。 系统表 GS_SQL_PATCH GS_SQL_PATCH系统表存储所有SQL_PATCH的状态信息。 系统视图 GLOBAL_SQL_PATCH GLOBAL_SQL_PATCH视图存放所有SQL PATCH的信息,该视图仅在pg_catalog模式下存在。 接口函数 DBE_SQL_UTIL Schema DBE_SQL_UTIL.create_hint_sql_patch create_hint_sql_patch是用于在当前建连的CN上创建调优SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.create_abort_sql_patch create_abort_sql_patch是用于在当前建连的CN上创建避险SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.drop_sql_patch drop_sql_patch是用于在当前建连的CN上删除SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.enable_sql_patch enable_sql_patch是用于在当前建连的CN上开启SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.disable_sql_patch disable_sql_patch是用于在当前建连的CN上禁用SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.show_sql_patch show_sql_patch是用于显示给定patch_name对应的SQL PATCH的接口函数,返回运行结果。 DBE_SQL_UTIL.create_hint_sql_patch create_hint_sql_patch是用于创建调优SQL PATCH的接口函数,返回执行是否成功。本函数是原函数的重载函数,支持通过parent_unique_sql_id值限制hint patch的生效范围。 DBE_SQL_UTIL.create_abort_sql_patch create_abort_sql_patch是用于创建避险SQL PATCH的接口函数,返回执行是否成功。本函数是原函数的重载函数,支持通过parent_unique_sql_id值限制abort patch的生效范围。 DBE_SQL_UTIL.create_remote_hint_sql_patch create_remote_hint_sql_patch是用于指定CN创建调优SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.create_remote_abort_sql_patch create_remote_abort_sql_patch是用于指定CN创建避险SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.drop_remote_sql_patch drop_remote_sql_patch是用于指定CN删除SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.enable_remote_sql_patch enable_remote_sql_patch是用于指定CN开启SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.disable_remote_sql_patch disable_remote_sql_patch是用于指定CN禁用SQL PATCH的接口函数,返回执行是否成功。
  • 特性约束 仅支持针对Unique SQL ID添加补丁,如果存在Unique SQL ID冲突,用于Hint调优的SQL PATCH可能影响性能,但不影响语义正确性。 仅支持不改变SQL语义的Hint作为PATCH,不支持SQL改写。 不支持逻辑备份、恢复。 不支持在DN上创建SQL PATCH。 仅初始用户、运维管理员、监控管理员、系统管理员用户有权限执行。 库之间不共享,创建SQL PATCH时需要连接目标库。如果创建SQL PATCH的CN被剔除并触发全量Build,则会继承全量Build的目标CN中的SQL PATCH,因此建议在各个CN上尽量都创建对应的SQL PATCH。 CN之间由于Unique SQL ID不同,不共享SQL PATCH,需要用户手动在不同的CN上创建对应的SQL PATCH。 限制在存储过程内的SQL PATCH和全局的SQL PATCH不允许同时存在。 使用PREPARE + EXECUTE语法执行的预编译语句执行不支持使用SQL PATCH。 SQL PATCH不建议在数据库中长期使用,只应该作为临时规避方法。遇到内核问题所导致的特定语句触发数据库服务不可用问题,以及使用Hint进行调优的场景,需要尽快修改业务或升级内核版本解决问题。并且升级后由于Unique SQL ID生成方法可能变化,可能导致规避方法失效。 当前,除DML语句之外,其他SQL语句(如CREATE TABLE等)的Unique SQL ID是对语句文本直接哈希生成的,所以对于此类语句,SQL PATCH对大小写、空格、换行等敏感,即不同的文本的语句,即使语义相同,仍然需要对应不同的SQL PATCH。对于DML,则同一个SQL PATCH可以对不同入参的语句生效,并且忽略大小写和空格。
  • 检查隐式转换的性能问题 在某些场景下,数据类型的隐式转换可能会导致潜在的性能问题。请看如下的场景: SET enable_fast_query_shipping = off; CREATE TABLE t1(c1 VARCHAR, c2 VARCHAR); CREATE INDEX on t1(c1); EXPLAIN verbose SELECT * FROM t1 WHERE c1 = 10; 上述查询的执行计划如下: c1的数据类型是varchar,当查询的过滤条件为c1 = 10时,优化器默认将c1隐式转换为bigint类型,导致两个后果: 不能进行DN裁剪,计划下发到所有DN上执行。 计划中不能使用Index Scan方式扫描数据。 这会引起潜在的性能问题。 当知道了问题原因后,我们可以做针对性的SQL改写。对于上面的场景,只要将过滤条件中的常量显示转换为varchar类型,结果如下: EXPLAIN verbose SELECT * FROM t1 WHERE c1 = 10::varchar; 为了提前识别隐式类型转换可能带来的性能影响,我们提供了一个guc option:check_implicit_conversions。打开该参数后,对于查询中出现的隐式类型转换的索引列,在路径生成阶段进行检查,如果发现索引列没有生成候选的索引扫描路径,则会通过报错的形式提示给用户。举例如下: SET check_implicit_conversions = on; SELECT * FROM t1 WHERE c1 = 10; ERROR: There is no optional index path for index column: "t1"."c1". 参数check_implicit_conversions只用于检查隐式类型转换引起的潜在性能问题,在正式生产环境中请关闭该参数(该参数默认关闭)。 在将check_implicit_conversions打开时,必须同时关闭enable_fast_query_shipping参数,否则由于后一个参数的作用,无法查看对隐式类型转换修复的结果。 一个表的候选路径可能包括seq scan和index scan等多个可能的数据扫描方式,最终执行计划使用的表扫描方式是由执行计划的代价来决定的,因此即使生成了索引扫描的候选路径,也可能生成的最终执行计划中使用其它扫描方式。 父主题: SQL调优指南
  • 语法格式 1 wlmrule("time_limit,max_execute_time,max_iops") 本参数仅在enable_thread_pool=on时对非sysadmin/monitoradmin用户执行的select类型的语句生效。 time_limit:SQL语句被标记为慢SQL的执行时长,取值为0-INT_MAX,CN和DN上均可生效。 max_execute_time:SQL语句的最大执行时间,执行时间超过该时长后被强制cancel退出,取值为0-INT_MAX,仅在DN上生效。当max_execute_time小于或等于time_limit时,该规则不生效。 max_iops:SQL语句被标记为慢SQL后最大iops上限,仅在use_workload_manager=on时生效。iops限制采用逻辑IO管控,iops定义请参考io_control_unit定义。取值范围为:Low,Medium,High,None,0-INT_MAX,仅在DN上生效。
  • 语法格式 1 2 3 4 predpush_same_level([@queryblock] src, dest) predpush_same_level([@queryblock] src1 src2 ..., dest) [no] nestloop_index([@queryblock] dest[, index_list]) -- 索引方式 [no] nestloop_index([@queryblock] dest[,(src1 src2 ...)]) -- 表名方式 predpush_same_level参数仅在rewrite_rule中的predpushforce选项打开时生效。 nestloop_index对rewrite_rule不做要求。
  • 示例 gaussdb=# deallocate all; DEALLOCATE ALL gaussdb=# prepare p1 as insert /*+ no_gpc */ into t1 select c1,c2 from t2 where c1=$1; PREPARE gaussdb=# execute p1(3); INSERT 0 1 gaussdb=# select * from dbe_perf.global_plancache_status where schema_name='public' order by 1,2; nodename | query | refcount | valid | databaseid | schema_name | params_num | func_id | pkg_id | stmt_id ----------+-------+----------+-------+------------+-------------+------------+---------+--------+--------- (0 rows) dbe_perf.global_plancache_status视图中无结果即没有计划被全局缓存。
  • 示例 强制使用Custom Plan 1 2 3 4 set enable_fast_query_shipping = off; create table t (a int, b int, c int); prepare p as select /*+ use_cplan */ * from t where a = $1; explain execute p(1); 计划如下。可以看到过滤条件为入参的实际值,即此计划为Custom Plan。 强制使用Generic Plan 1 2 3 deallocate p; prepare p as select /*+ use_gplan */ * from t where a = $1; explain execute p(1); 计划如下。可以看到过滤条件为待填充的入参,即此计划为Generic Plan。
  • 参数说明 @queryblock 见指定Hint所处的查询块Queryblock章节,可省略,表示在当前查询块生效,该hint只在指定为最外层的queryblock时才会生效。 param:表示参数名。 value:表示参数的取值。 目前支持使用Hint设置生效的参数有: 布尔类: enable_bitmapscan、enable_hashagg、enable_hashjoin、enable_indexscan、enable_indexonlyscan、enable_gsiscan、enable_material、enable_mergejoin、enable_nestloop、enable_index_nestloop、enable_seqscan、enable_sort、enable_tidscan、enable_stream_operator、enable_stream_recursive、enable_broadcast、enable_fast_query_shipping、enable_trigger_shipping、enable_remotejoin、enable_remotegroup、enable_remotelimit、enable_remotesort、enable_inner_unique_opt 整型类: best_agg_plan,query_dop 浮点类: cost_weight_index、default_limit_rows、seq_page_cost、random_page_cost、cpu_tuple_cost、cpu_index_tuple_cost、cpu_operator_cost、effective_cache_size 字符串类: node_name 通过设置node_name可以指定当前的sql下发到node_name对应的dn上去执行。 示例: select /*+ set(node_name datanode1) */ from table_name; 其中,datanode1是从 pgxc_node 系统表里查询出来的数据节点的名称(不用加引号),table_name 是表名。该查询表示直接去datanode1上执行查询。 node_name只支持在select语句里设置,如果在其他语句里设置将会不生效。 node_name只支持设置data node名字,不支持设置coodninator名字。 node_name不支持通过SET语句进行修改,只能用在plan hint里。 node_name不支持通过gs_guc进行修改。 node_name仅支持简单查询语句,不支持带union,union all子查询,多表关联等复杂查询语句。 支持普通用户执行。 不支持与行级访问控制同时使用,同时使用会报错。 设置不在白名单中的参数,参数取值不合法,或hint语法错误时,不会影响查询执行的正确性。使用explain(verbose on)执行可以看到hint解析错误的报错提示。 GUC参数的hint只在最外层查询生效,子查询内的GUC参数hint不生效。 视图定义内的GUC参数hint不生效。 CREATE TABLE ... AS ... 查询最外层的GUC参数hint可以生效。
  • Hint的错误、冲突及告警 Plan Hint的结果会体现在计划的变化上,可以通过explain来查看变化。 Hint中的错误不会影响语句的执行,只是不能生效,该错误会根据语句类型以不同方式提示用户。对于explain语句,hint的错误会以warning形式显示在界面上,对于非explain语句,会以debug1级别日志显示在日志中,关键字为PLANHINT。 hint的错误分为以下类型: 语法错误 语法规则树归约失败,会报错,指出出错的位置。 例如:hint关键字错误,leading hint或join hint指定2个表以下,其它hint未指定表等。一旦发现语法错误,则立即终止hint的解析,所以此时只有错误前面的解析完的hint有效。 例如: 1 leading((t1 t2)) nestloop(t1) rows(t1 t2 #10) nestloop(t1)存在语法错误,则终止解析,可用hint只有之前解析的leading((t1 t2))。 语义错误 表不存在,存在多个,或在leading或join中出现多次,均会报语义错误。 scanhint中的index不存在,会报语义错误。 另外,如果子查询提升后,同一层出现多个名称相同的表,且其中某个表需要被hint,hint会存在歧义,无法使用,需要为相同表增加别名规避。 hint重复或冲突 如果存在hint重复或冲突,只有第一个hint生效,其它hint均会失效,会给出提示。 hint重复是指,hint的方法及表名均相同。例如:nestloop(t1 t2) nestloop(t1 t2)。 hint冲突是指,table list一样的hint,存在不一样的hint,hint的冲突仅对于每一类hint方法检测冲突。 例如:nestloop (t1 t2) hashjoin (t1 t2),则后面与前面冲突,此时hashjoin的hint失效。注意:nestloop(t1 t2)和no mergejoin(t1 t2)不冲突。 leading hint中的多个表会进行拆解。例如:leading ((t1 t2 t3))会拆解成:leading((t1 t2)) leading(((t1 t2) t3)),此时如果存在leading((t2 t1)),则两者冲突,后面的会被丢弃。(例外:指定内外表的hint若与不指定内外表的hint重复,则始终丢弃不指定内外表的hint。) 子链接提升后hint失效 子链接提升后的hint失效,会给出提示。通常出现在子链接中存在多个表连接的场景。提升后,子链接中的多个表不再作为一个整体出现在join中。 列类型不支持重分布 对于skew hint来说,目的是为了进行重分布时的调优,所以当hint列的类型不支持重分布时,hint将无效。 hint未被使用 非等值join使用hashjoin hint或mergejoin hint。 不包含索引的表使用indexscan hint或indexonlyscan hint。 不包含全局二级索引的表使用gsi hint。 通常只有在索引列上使用过滤条件才会生成相应的索引路径,全表扫描将不会使用索引,因此使用indexscan hint、indexonlyscan hint或gsi hint将不会使用。 indexonlyscan只有输出列仅包含索引列才会使用,否则指定时hint不会被使用。 gsi只有查询能够下推至全局二级索引时才会使用,否则不会被使用。 多个表存在等值连接时,仅尝试有等值连接条件的表的连接,此时没有关联条件的表之间的路径将不会生成,所以指定相应的leading,join,rows hint将不使用,例如:t1 t2 t3表join,t1和t2, t2和t3有等值连接条件,则t1和t3不会优先连接,leading(t1 t3)不会被使用。 生成stream计划时,如果表的分布列与join列相同,则不会生成redistribute的计划;如果不同,且另一表分布列与join列相同,只能生成redistribute的计划,不会生成broadcast的计划,指定相应的hint则不会被使用。 如果子链接未被提升,则blockname hint不会被使用。 对于skew hint,hint未被使用可能由于: 计划中不需要进行重分布。 hint指定的列为包含分布键。 hint指定倾斜信息有误或不完整,如对于join优化未指定值。 倾斜优化的GUC参数处于关闭状态。 父主题: 使用Plan Hint进行调优
  • 参数说明 @queryblock 见指定Hint所处的查询块Queryblock章节,可省略,表示在当前查询块生效。 src, src1, src2表示predpush下推candidates一侧表集合。 dest表示predpush下推所指定的dest表也就是目标表。 predpush如果没有逗号表示所有表都是candidates表, 如果有逗号就说明同时指定了candidates表和dest表。 使用predpush hint将过滤表达式尽可能移至靠近数据源的位置以达到查询优化的目的。 使用predpush hint需要确保rewrite_rule GUC参数包含PREDPUSH|REDPUSHFORCE|PREDPUSHNORMAL选项。 subquery_block也可以是视图/物化视图。
  • 参数说明 @queryblock 见指定Hint所处的查询块Queryblock章节,可省略,表示在当前查询块生效。 “#”、“+”、“-”、“*”,进行行数估算hint的四种操作符号。#表示直接使用后面的行数进行hint。“+”、“-”、“*”表示对原来估算的行数进行加、减、乘操作,运算后的行数最小值为1行。table_list为hint对应的单表或多表join结果集,与Join方式的Hint中table_list相同。
  • 建议 推荐使用两个表*的hint。对于两个表的采用*操作符的hint,只要两个表出现在join的两端,都会触发hint。例如:设置hint为rows(t1 t2 * 3),对于(t1 t3 t4)和(t2 t5 t6)join时,由于t1和t2出现在join的两端,所以其join的结果集也会应用该hint规则乘以3。 rows hint支持在单表、多表、function table及subquery scan table的结果集上指定hint。
  • 参数说明 join_table_list为表示表join顺序的hint字符串,可以包含当前层的任意个表(别名),或对于子查询提升的场景,也可以包含子查询的hint别名,同时任意表可以使用括号指定优先级,表之间使用空格分隔。 @queryblock 见指定Hint所处的查询块Queryblock章节,可省略,表示在当前查询块生效。 表只能用单个字符串表示,不能带schema。 表如果存在别名,需要优先使用别名来表示该表。
  • 参数说明 relname为查询中表table的名字,表有别名时,需要优先使用别名alias,此时relname=alias。当表名中有特殊符号,比如“@”、“.”时,relname需要用""括起来,以避免和查询块和schema名的声明重合。比如表名relnametest@1,需要写做 "relnametest@1"。 schema为表所处的schema,可缺省,缺省时Hint不区分schema对relname进行查找。 queryblock为表所处的queryblock,可缺省,缺省时Hint不区分queryblock对relname进行查找。
共100000条