-
问题原点查sql执行时间较慢explain analyseselect * from a.bwhere data_time >= '2025-11-26 00:00:00' and data_time <= '2025-11-26 23:559:59' and id = '911221441502800';分析打执行计划analyse进行分析QUERY PlANid|Operaton|A-time|A-rows|E-rows|Peak Memory|E-memory|A-width------------------------------------------------------------------------------1|->Row Adapter |7009.173 | 672丨 2083 | 377K8 2| ->Vector Streaming (type: GATHER) | 7008.273 | 672丨 2083 | 2019KB3| ->Vector Partition Iterator | [80.898,6985.116]丨672 | 2083 | [16kb,16kb] | 1MB4| ->Partitioned CStore Scan on a.b | (80.802, 6983.967)] | 672丨 2083 | [8MB,26MB] |15MB查询当前table表定义,分布键为run_id,分区键为data_time,查询条件为id,该查询中由data_time筛选到某个分区后,由id再次进行数据筛选时,筛选到的这部分数据倾斜,观察table已建立id的二级分区。继续观察执行计划 ,耗时集中在scan hstore delta,该算子从delta表中取数。hstore_opt表中的delta表用途为解决1、小批量数据入库导致小CU问题;2、以及对列存表更新/删除导致列存表膨胀问题。在执行多次小批量插入后,delta merge将数据从delta表存储转到hstore_opt表中,delta表空间会正常得到回收。现网实际业务场景,实时数据入库速度远大于delta merge速度,delta merge无法及时回收delta表空间,就出现delta表膨胀,进一步影响查询性能。Plan Node id: 3 Track name: coordinator handle data from all connections(actual time=[1.274, 1.274], calls=[60, 60])Plan Node id: 6 Track name: load CU description(actual time=[86.899, 111.336], calls=[125367, 125815])Plan Node id: 6 Track name: min/max check(actual time=[22.734, 30.065], calls=[2062, 2080])Plan Node id: 6 Track name: fill vector batch(actual time=[3401.005, 4123.678], calls=[121274, 121701])Plan Node id: 6 Track name: get CU data(actual time=[2739.232, 3461.872], calls=[242548, 243402])Plan Node id: 6 Track name: uncompress CU data(actual time=[1254.232, 1514.954], calls=[4074, 4110])Plan Node id: 6 Track name: apply projection and filter (actual time=[10568.756, 10981.310], calls=[242249,243080])Plan Nore id: 6 Track name: scan hstore delta(actual time=[1007.184, 12737.321], calls=[2083, 2129])Plan Nore id: 6 Track name: fill later vetor batch(actual time=[13.639, 17.033], calls=[121274, 121701])Plan Node id: 6 Track name: heap scan read buffer (sample time=[13.043, 1147.751], estimated time=[130.470, 11477.527]...解决方案使用hstore_full_merge进行手动merge
-
问题 同一个SQL、同样的数据量,配置了定时任务,运行一段时间后脚本没法执行了或执行时间成指数增长、最终运行超时失败分析对比执行成功与未执行成功的执行计划。此处分析的是27号凌晨1点发起的成功查询的执行计划,与27号早9点发起的未成功查询出结果执行一段时间后被停止的失败执行计划。观察到执行失败的执行计划(下称失败计划)的36号算子与执行成功的执行计划(下称成功计划)的43号算子出现差别,此处为dnb表进行m表关联:类似于select * from dnb,m where dnb.area_code=m.area_code and dnb.run_id=m.fun_id.成功计划做了hash right join,可以看到此时优化器判断小表是45号算子也就是m表,故将m表的area_code与fun_id在内存中建立哈希表,然后扫描较大的表也就是dnb表,去探测哈希表m表,找到与散列匹配的行。失败计划做了sonic hash join,是一种优化后的Inner Join,此时优化器判断37号算子也就是dnb表为小表。失败计划的inner join错误判断将大表dnb做了内表。36 ->Vetor Sonic Hash Join(37,38) (cost=695225.73...6310390.15 rows=28378940 width=46) Hash Cond:((dnb.area_code = m.area_code) AND (dnb.run_id=m.fun_id)) Generate Bloom Filter On Expr:m.area_code, m.fun_id Generate Bloom Filter On Index: 0, 1 Generate Runtime Filter Type: MinMax, MinMax---------------------------------分界,以上是失败sql,以下是成功sql-----------------43 ->Vector Hash Right Join (44,45)(cost=759485.18...8206060.95 rows=83208991 width=46) (actual time=[2069.824,5826.664]... Hach Cond ((dnb.run_id=m.fun_if) AND (dnb.area_code=m.area_code)) Generate Bloom Filter On Expr:m.fun_id, m.area_code Generate Bloom Filter On Index: 0,1 Generate Runtime Filter Type: MinMax, MinMax Max Memory Used : 315268KB Min Memory Used : 314900KB查询dnb与m表两次关联存在区别的原因,查询两表最后的analyse时间,两张表的analyse时间为null,也就是从未被执行过auto analyse,及从未被收集过执行计划。查看两表数量,都为5000w条数据,且业务反馈两表时间每次变化数据量不大。因触发auto analyse的条件是变化数据量的10%,优化器、认为数据特征未有变化,故一直未收集统计信息。统计信息不准导致优化器生成执行计划时对数据进行采样,每次采样到的数据不一致导致执行计划存在差别。故执行时间不一样。查询analyse收集时间select * from pg_stat_get_last_analyze_time('dnb'::regclass);---------------------------pg_stat_get_last_analyzenull select * from pg_stat_get_last_analyze_time('m'::regclass);---------------------------pg_stat_get_last_analyzenull 结论多表关联时,错误的统计信息,会使得大表做内表,可能导致无法全部加载进而数据下盘。 现网问题的根本原因为数据变化较少->统计信息未收集->优化器每次生成的执行计划存在差别->偶发生成不匹配的执行计划导致查询过长。 补充:有时候给出解决方法比找出原因更难,因为遇到这种问题大概率就是大表做了内表,但原因呢,藏得很深。
-
问题 同一个SQL、同样的数据量,配置了定时任务,运行一段时间后脚本没法执行了或执行时间成指数增长、最终运行超时失败分析对比执行成功与未执行成功的执行计划。此处分析的是27号凌晨1点发起的成功查询的执行计划,与27号早9点发起的未成功查询出结果执行一段时间后被停止的失败执行计划。观察到执行失败的执行计划(下称失败计划)的36号算子与执行成功的执行计划(下称成功计划)的43号算子出现差别,此处为dnb表进行m表关联:类似于select * from dnb,m where dnb.area_code=m.area_code and dnb.run_id=m.fun_id.成功计划做了hash right join,可以看到此时优化器判断小表是45号算子也就是m表,故将m表的area_code与fun_id在内存中建立哈希表,然后扫描较大的表也就是dnb表,去探测哈希表m表,找到与散列匹配的行。失败计划做了sonic hash join,是一种优化后的Inner Join,此时优化器判断37号算子也就是dnb表为小表。失败计划的inner join错误判断将大表dnb做了内表。36 ->Vetor Sonic Hash Join(37,38) (cost=695225.73...6310390.15 rows=28378940 width=46) Hash Cond:((dnb.area_code = m.area_code) AND (dnb.run_id=m.fun_id)) Generate Bloom Filter On Expr:m.area_code, m.fun_id Generate Bloom Filter On Index: 0, 1 Generate Runtime Filter Type: MinMax, MinMax---------------------------------分界,以上是失败sql,以下是成功sql-----------------43 ->Vector Hash Right Join (44,45)(cost=759485.18...8206060.95 rows=83208991 width=46) (actual time=[2069.824,5826.664]... Hach Cond ((dnb.run_id=m.fun_if) AND (dnb.area_code=m.area_code)) Generate Bloom Filter On Expr:m.fun_id, m.area_code Generate Bloom Filter On Index: 0,1 Generate Runtime Filter Type: MinMax, MinMax Max Memory Used : 315268KB Min Memory Used : 314900KB查询dnb与m表两次关联存在区别的原因,查询两表最后的analyse时间,两张表的analyse时间为null,也就是从未被执行过auto analyse,及从未被收集过执行计划。查看两表数量,都为5000w条数据,且业务反馈两表时间每次变化数据量不大。因触发auto analyse的条件是变化数据量的10%,优化器、认为数据特征未有变化,故一直未收集统计信息。统计信息不准导致优化器生成执行计划时对数据进行采样,每次采样到的数据不一致导致执行计划存在差别。故执行时间不一样。查询analyse收集时间select * from pg_stat_get_last_analyze_time('dnb'::regclass);---------------------------pg_stat_get_last_analyzenull select * from pg_stat_get_last_analyze_time('m'::regclass);---------------------------pg_stat_get_last_analyzenull 结论多表关联时,错误的统计信息,会使得大表做内表,可能导致无法全部加载进而数据下盘。 现网问题的根本原因为数据变化较少->统计信息未收集->优化器每次生成的执行计划存在差别->偶发生成不匹配的执行计划导致查询过长。 补充:有时候给出解决方法比找出原因更难,因为遇到这种问题大概率就是大表做了内表,但原因呢,藏得很深。
-
1、分析 原sql如下#原sqlselect * from a.b where data_time >= '2025-11-12 00:00:00' and data_time <= '2025-11-12 23:59:59' and id = '1233333';查询sql执行计划,耗时5s,最长耗时集中在cstore scan,即列存表底层数据查询。QUERY PlANid|Operaton|A-time|A-rows|E-rows|Peak Memory|E-memory|A-width------------------------------------------------------------------------------1|->Row Adapter |7009.173 | 672丨 2083 | 377K8 2| ->Vector Streaming (type: GATHER) | 7008.273 | 672丨 2083 | 2019KB3| ->Vector Partition Iterator | [80.898,6985.116]丨672 | 2083 | [16kb,16kb] | 1MB4| ->Partitioned CStore Scan on a.b | (80.802, 6983.967)] | 672丨 2083 | [8MB,26MB] |15MB继续观察详细执行计划,fill later vector batch耗时4s,该算子的含义是从宽表中填充数据,及从宽表中select *。如果把select *修改为select 必要列,该算子耗时会减少。同时观察到查询中存在计算倾斜,查询时间较短的dn耗时7ms,但查询时间较长的dn耗时4480ms。Plan Node id:4 Track name:fill later vector batchdn_6001_6002(time=7.913 total calls=81 loops=1) dn_6005_6006(time=157.372 total calls=57 loops=1)dn_6007_6008(time=49.778 total calls=61 loops=1)dn_6009_6010(time=4480.398 total calls=84 loops=1)dn_6023_6024(time=9.027 total calls=55 loops=1) 2、结论查询时间的主要耗时在fill later vector batch,该算子的含义是从宽表中填充数据。1、 计算倾斜导致数据分布不平均,个别dn计算时间过长导致整体时间较长; 即id筛选的数据在dn上倾斜。查看表倾斜,未出现倾斜,即:分布键与id筛选列具有强相关性,分布键未将id数据打散至各dn,建议重新选择分布键,将id均匀打散到各dn。2、 查询中使用了select *,导致填充数据较多,从而耗时较长。
-
物联网技术未来发展趋势如何?
-
导出数据cid:link_6计划诊断cid:link_7共享自定义数据源cid:link_0IAM用户导出按钮权限配置cid:link_8新增目录cid:link_1数据开发设置cid:link_9sql_dialect插件实现SQL自由兼容cid:link_2不可定义IMMUTABLE的几种情况cid:link_10下推属性cid:link_3入参含NULL处理cid:link_4如何写出性能最优的函数cid:link_11函数内设置GUC变量优化cid:link_12函数变更cid:link_13查询过滤器cid:link_5权限问题https://bbs.huaweicloud.com/forum/thread-0293199787641436055-1-1.html
-
对于普通用户来讲是没有创建查询过滤规则权限的,需要管理员或者管理员将权限赋给某一普通用户才可以。建议创建查询过滤规则时尽量缩小适用范围,避免误过滤,或者范围过大导致性能劣化。对于查询过滤规则的备份或者恢复的权限与操作元数据的权限一致,需要管理员或者管理员讲权限赋值给某一普通用户才可以,用户可以通过gs_dump导出查询过滤规则定义。如果想查看或者导入查询过滤规则的定义,可以通过pg_get_blockruledef进行查询。所有的查询过滤规则元数据全部保存在pg_blocklists系统表中,可以通过查看系统表浏览所有的查询过滤规则。查询语句包含了tt关键字,并且扫描的分区个数超过了2,此时执行语句被过滤拦截。需要注意的是,扫描分区的个数并不总是准确的,仅能识别静态的分区剪枝个数,执行过程中的动态剪枝并不能被识别。使用关键词过滤时可以先使用正则匹配符~*进行测试,正则匹配是忽略大小写的。另外,由于查询过滤器的规则直接作用在用户block_user上,因此在删除用户block_user时,会提示有依赖项,此时可以通过在语句最后加上cascade进行删除,此时作用在此用户上的查询过滤规则也会被一同删除。需要注意的是,过滤规则命中的依据是,with_parameter命中任意一项,且其他字段的特征也符合即会判定为符合查询过滤规则。
-
在业务开发过程中,要想禁止对2张以上的表进行关联查询,此时可以使用DDL语句创建过滤规则:table_num指的是一个语句中出现的表的个数,此时所有查询语句不能包含有两张表以上的查询。整体逻辑就非常清楚了。用户可以提前识别烂SQL的特征,然后抽象出来,用DDL语句创建规则,后续会对查询的语句进行过滤,被规则筛选出来的便是烂SQL,执行前会报错,反之则可以正常执行。之前的查询过滤器的功能依然存在,可以保证与异常规则的联动,新版本的增强更注重规则的灵活性和功能的丰富性。查询过滤规则,可以通过DDL进行新增、删除或者修改,其语法如下:block_name: 过滤规则的名称user_name: 规则应用的对象用户host: 是规则应用的客户端IPFOR: 语句类型,支持对UPDATE/SELECT/INSERT/DELETE/MEGE INTO五种类型语句进行限制FILTER BY: 过滤方法,包含两种形式SQL: 根据关键词对语句进行正则匹配,例如表名,其长度不能超过1024,建议尽量精简TEMPLATE:sql_hash:归一化的哈希值(md5),一般不会重复,相较unique_sql_id更推荐使用。unique_sql_id:归一化的64位哈希值,重复概率较sql_hash大一些。with_parameter: 查询过滤规则选项参数,可以附加多个条件,满足其一便会匹配过滤。application_name: 客户端名称query_band: 负载标识table_num: 包含的基表个数partition_num: 扫描分区的数量estimate_row: 基表输出行数resource_pool: 切换的目标资源池,仅适用于9.1.0.200及以上max_active_num: 可并发执行的语句个数,仅适用于9.1.0.200及以上is_warning: 改变拦截行为为告警,而非默认的报错,仅适用于9.1.0.200及以上其中,user_name和FILTER BY是必选项,其他可以通过业务实际需要进行配置。
-
函数参数个数和类型,一旦定义,不允许变更。防止用户业务报错。函数行为也禁止前后不兼容的变更,如果必须要变,需要在内核加GUC参数进行控制。这样也造成了与内核的依赖。将新函数放入dialects目录对应的方言文件中,同时还要在升级脚本中再进行处理。通过独立C函数(少量使用内核基础函数),都可以放入插件。在插件中现有或新增的cpp中编写函数。查询过滤器在9.1.0.100之前就具备提供查询过滤功能的能力,但仅支持自动隔离反复查询被终止的查询,防止烂SQL再次执行。老版本主要面向异常熔断机制和紧急拦截场景,前者可以与异常规则联动,自动将触发异常规则的语句添加到黑名单中,后者是需要手动找到core或者引发hang的语句进行屏蔽。9.1.0.100及9.1.0.200版本对查询过滤器做了功能的改进,可以通过多维度进行烂SQL识别,功能更丰富,配置更灵活。
-
尽量避免在函数内部设置环境变量,SET会多CN执行,造成不必要的通信开销。VOLATILE属性的SQL语言函数会频繁访问GTM,性能差,且给GTM造成比较大的压力。因此,LANGUAGE为SQL的函数,尽量不要定义为VOLATILE。函数参数的类型和返回值类型,要严格注意。避免类型转换导致的core或结果集错误。一些常见错误:应该返回timestamptz,而返回了text。结果看似一样,实际无法使用。应该返回timestamptz,而返回了timestamp,丢失了时区,未注意到。不兼容类型的强制转换,导致C函数调用core。调用内存C函数时,需要传入timestamptz类型,却给了timestamp类型,导致时区转换错误。能自动隐式类型转换的类型,尽量只写一个函数。例如:text和timestamp都可以向timestamptz自动转换,不必每个类型都实现一个相似函数。尽量使用pg原生函数定义新函数。因为兼容性函数可能因为各种兼容性导致后期修改,从而级联导致新函数结果集不稳定。
-
类似C++中的inline能力,如果是简短的计算或转换函数,正确的书写为满足inline特征的函数,则优化器可将函数调用优化成表达式执行,明显提升执行性能。可被优化器自动优化为 ```$1 + $2``` 的表达式。下面执行计划输出的Output已不再是函数调用,而是优化为(a+b)表达式。inline函数要求:函数类型,LANGUAGE必须是SQL类型。函数易变性,不能是VOLATILE,且易变性不高于函数体内的语句。例如:函数体内调用的函数其易变性为STABLE,则该函数只能是STABLE,不能是IMMUTABLE。从高到底按照IMMUTABLE STABLE VOLATILE排序。函数strict属性,必须与函数体内包含的函数strict一致。函数体,函数中必须为简单的单条select语句,不含group by等复杂逻辑。函数返回值,函数内语句返回类型必须与该函数返回类型一致,且不能是set和record等复杂类型。入参含NULL优化入参含NULL返回值也肯定为NULL的函数,要显示定义STRICT属性。这样当入参含NULL时,可以减少函数体的调用执行。函数类型选择从性能方面考虑,尽量按照SQL函数>C函数>plpgsql函数顺序选择函数类型。SQL函数简单计算优先使用SQL类型,尽量满足inline特征。C函数非单条语句的函数建议定义为C函数申请的内存要用完及放保护模式必须显示定义为DENCED模式入参和返回值类型严格注意,避免类型不一致或强制转换导致core或结果集问题。
-
CALLED ON NULL INPUT(默认):表明该函数的某些参数是NULL的时候可以按照正常的方式调用该函数,函数开发者需自己做判空处理。RETURNS NULL ON NULL INPUT或STRICT:如果声明了这个参数,当有NULL值参数时该函数不会被执行;而只是自动返回一个NULL结果。RETURNS NULL ON NULL INPUT和STRICT的功能相同。入参含NULL返回值也为NULL的,尽量显示定义STRICT。保护模式声明用户定义的C函数是否在保护模式下执行。FENCED模式(默认):则函数在新fork的进程执行,这样函数的异常不会影响CN或者DN进程。NOT FENCED模式:函数的执行在CN或者DN进程中进行;如何选择:正在开发或者调试的Function使用FENCED模式。开发测试完成,使用NOT FENCED模式执行,减少fork进程以及通信的开销。复杂的操作系统操作,例:打开文件,信号处理,线程处理等操作,使用FENCED模式。否则可能影响GaussDB(DWS)数据库的执行。C函数必须是FENCED模式。
-
SHIPPABLE:表示该函数可以下推到DN上执行。NOT SHIPPABLE(默认):表示该函数不可以下推到DN上执行。注意:对于IMMUTABLE函数,不管SHIPPABLE如何设置,函数始终可以下推到DN上执行。对于STABLE/VOLATILE函数,当且仅当函数属性是SHIPPABLE的时候,函数才可以下推到DN执行。定义SHIPPABLE属性时需特别慎重,SHIPPABLE意味着整个函数会下推到DN上执行,如果设置不当,会导致结果错误等严重问题。与定义IMMUTABLE属性一样,SHIPPABLE属性的定义也有诸多约束,简单来说就是函数体内不能有不可下推的因素,函数下推到单DN执行后,函数内部的计算逻辑仅依赖当前DN的数据集合。举例如下:如果函数内部引用了表,并且表为HASH分布,那么该函数通常不能定义为SHIPPABLE。函数内部有不可下推的因素,函数,语法等,那么该函数不能定义为SHIPPABLE,可参考语句下推调优。函数内部的计算过程可能需要跨DN数据,这种情况该函数通常不能定义为SHIPPABLE,例如一些聚合运算等。
-
函数中引用了表,视图等对象,因为当表的数据发生变化的时候,函数的返回值可能发生变化。函数中引用了STABLE/VOALATILE类型的函数,那么该函数不能定义为IMMUTABLE。函数中有不下推的因素,因为IMMUTABLE意味着要下推到DN执行,与函数体内部的不下推因素相互冲突。典型场景例如,包含不下推的函数、语法等。函数中含有聚合运算,但聚合运算的运算需要生成STREAM计划才能完成计算的(部分结果在DN计算,部分结果在CN计算,例如listagg函数等)。为了防止错误定义IMMUTABLE可能导致严重问题,数据库内部可以通过设置behavior\_compat\_options=‘check\_function\_conflicts’来开启对函数定义冲突的检查,目前可以识别出上述1和2场景。
-
sql_dialect插件是DWS用于支持各种SQL方言的插件包。优先级:方言插件中函数优先级高于数据库内核中的函数,便于解决与内核的冲突。绑定方言:每一个数据库可以独立绑定方言插件,与CREATE DATABASE时选择的DBCOMPATIBILITY没有关联关系,但建议保持一致。修改方言:方言插件一旦绑定,不支持修改,除非先卸载插件再重新绑定。插件基础能力:支持简单SQL实现的函数,支持plpgsql实现的函数,支持C实现的函数,支持独立的升降级,与内核升降级无关,可以通过管控面平台,快速发布升级。VOLATILE(默认): 表示函数返回值在一次表扫描内随时可以改变,例如:random, currval, timeofday等。这也导致这些函数不会被做任何优化。STABLE: 表示对相同函数入参,在同一次表扫描里,该函数的返回值不会变,但是在同一会话的不同SQL多次调用时可能会变化。IMMUTABLE: 表示该函数在相同入参时总是返回同样的结果。也就是说该函数不会通过查询数据库,GUC参数,随机数,当前时间等可能不确定性的因素来生成函数返回值。如果入参是常量,这类函数可以直接被优化器替换为函数值,减少函数调用。注意:IMMUTABLE函数会被自动下推到DN执行,如果用户错误定义了函数的IMMUTABLE属性,那么可能会导致结果集错误。因此,用户在指定函数的属性为IMMUTABLE的时候,要特别慎重。
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签