转载自GBASE南大通用官方社区:https://www.gbase.cn/community/post/3753
2024年5月的某天早上,客户发来如下的问候:
南大通用GBase 8c的DBA们,早上好,项目遇到一个SQL查询的问题,想要请教下,当一个SQL的select部分存在函数时,是否是先用函数计算结果,再计算where条件的结果?
其实这个问题本身问的有些模糊,但客户马上又补充道:
目前有个SQL,在有函数,和没有函数的情况下,查询速度差异巨大,有函数执行要9秒钟,没有函数的时候0.05秒就执行完了。但之前在Oracle下执行是很快的。
南大通用GBase 8c在分布式形态部署下,既有强大的并行处理能力,又可以保证分布式事务的实时一致性,通常情况下都能够达到比Oracle等传统集中式数据库更快的性能。
那么……
先看看具体SQL——
SELECT compare_date ( '2024-05-23 17:32:01', T.START_TIME ) AS START_TIME1, compare_date ( '2024-05-23 17:32:01', T.END_TIME ) AS END_TIME1 FROM ( SELECT acc.res_id, authz.START_TIME, authz.END_TIME, authz.FOREVER_TIME AS FOREVER_TIME1 FROM u_oper_authz authz INNER JOIN u_res_account acc ON authz.target_id = acc.ID WHERE authz.auth_type = 'resAccount' AND authz.user_id = '673487257655296' AND authz.tenant = 'fe0307d50b584aacbe283cc9600419d7' AND authz.LOGIC_DELETE = '0' AND acc.LOGIC_DELETE = '0' ) T
经过几轮对话,客户的疑问其实在于compare_date ( '2024-05-23 17:32:01', T.START_TIME ) 这个函数,如果只查询T.START_TIME和T.END_TIME速度很快,但如果带上compare_date 函数就很慢。
而且在Oracle下执行没有问题,为什么迁移到分布式架构的南大通用GBase 8c上就会有问题呢?
其实经验丰富的8c DBA们看到这里已经可以判断出问题所在了,但这的确又是函数从Oracle这类传统集中式架构数据库中迁移到南大通用GBase 8c分布式形态时的常见问题。
再看看执行计划——
有函数时 Hash Join (cost=107938.71..166726.88 rows=1037 width=38) Hash Cond: ((authz.target_id)::text = (acc.id)::text) -> Data Node Scan on u_oper_authz "_REMOTE_TABLE_QUERY_" (cost=0.00..0.00 rows=1000 width=71) Node/s: All datanodes -> Index Scan using idx_uoperauthz_userid on u_oper_authz authz (cost=0.00..257.80 rows=117 width=71) Index Cond: ((user_id)::text = '673487257655296'::text) Filter: (((auth_type)::text = 'resAccount'::text) AND ((tenant)::text = 'fe0307d50b584aacbe283cc9600419d7'::text) AND ((logic_delete)::text = '0'::text)) -> Hash (cost=0.00..0.00 rows=1000 width=33) -> Data Node Scan on u_res_account "_REMOTE_TABLE_QUERY_" (cost=0.00..0.00 rows=1000 width=33) Node/s: All datanodes -> Seq Scan on u_res_account acc (cost=0.00..85746.60 rows=1321708 width=33) Filter: ((logic_delete)::text = '0'::text)
没有函数时 Streaming(type: GATHER) (cost=0.00..444.62 rows=173 width=72) Spawn on: All datanodes -> Nested Loop (cost=0.00..440.67 rows=1037 width=72) -> Streaming(type: REDISTRIBUTE) (cost=0.00..273.37 rows=720 width=72) Spawn on: All datanodes -> Index Scan using idx_uoperauthz_userid on u_oper_authz authz (cost=0.00..263.47 rows=720 width=72) Index Cond: ((user_id)::text = '673487257655296'::text) Filter: (((auth_type)::text = 'resAccount'::text) AND ((tenant)::text = 'fe0307d50b584aacbe283cc9600419d7'::text) AND ((logic_delete)::text = '0'::text)) -> Index Scan using u_res_account_pkey on u_res_account acc (cost=0.00..1.38 rows=1 width=66) Index Cond: ((id)::text = (authz.target_id)::text) Filter: ((logic_delete)::text = '0'::text)
可以看到,在没有函数时,执行计划走的是Stream。
这里就需要再插播一下南大通用GBase 8c分布式形态下的部署架构了
分布式形态的GBase 8c
GBase 8c数据库分布式形态采用share nothing的分布式架构,计算节点和存储节点分离,节点间通过高速网络进行通信,所有节点都有主从互备,确保系统的高可用性。由于没有资源共享,增加节点就可以线性地扩展集群的存储能力和计算能力,满足业务规模增长的要求。
GBase 8c支持SQL透传、SQL 下推、执行计划下推、数据上拉多种分布式查询执行方式,可根据实际的SQL命令自动选择最高效的执行方式,从而提高了分布式查询的执行效率。
问题根因
所以这次问题的真正原因,在于compare_date这个函数影响了该SQL的下推,并没有把该函数下推到DN节点去并行执行,而是把所有数据上拉到CN节点统一执行,最终造成了执行时间上近200倍的差距。
算子下推是GBase 8c关键技术之一,可以把各种复杂的SQL进行下推执行,最小化数据移动,这是相对于基于分库分表的中间件方案的核心优势。
最后看看这个“罪魁祸首”函数——
compare_date函数定义
CREATE OR REPLACE FUNCTION public.compare_date(s_date character varying, t_date character varying) RETURNS integer LANGUAGE plpgsql NOT FENCED NOT SHIPPABLE AS $function$ BEGIN IF(to_timestamp(trim(s_date),'yyyy-mm-dd hh24:mi:ss') > to_timestamp(trim(t_date),'yyyy-mm-dd hh24:mi:ss')) then RETURN 1; ELSE RETURN - 1; END IF; EXCEPTION WHEN others THEN RETURN - 2; END; $function$;
这里最关键的是第4行的 NOT SHIPPABLE
在GBase 8c中,使用SHIPPABLE和NOT SHIPPABLE来表示该函数是否可以下推到DN上执行,当前函数中使用的 NOT SHIPPABLE,意味着不允许下推到DN节点去并行处理,而是要把所有DN节点上的数据汇总拉到CN节点后,再在CN节点对全部数据进行函数运算操作。显然无论计算资源还是网络传输方面都需要有相应的投入。
而SHIPPABLE则可以将函数下推到DN上执行,可以实现并行处理,同时由于全量数据已经分散到多个DN节点上,因此并行处理的结果集更小,从而达到近200倍的性能提升。
一个函数是否允许下推,就要看函数具体的业务逻辑是否必须要在全量数据集上运算。对于本问题中的函数,本意是单独对每一个值进行日期比较的计算,并不涉及聚合操作,因此完全可以去掉NOT,改为SHIPABLE,从而将函数计算下推到DN节点执行。
问题解决
改为SHIPPABLE后,客户再次执行,可以看到右下角运行时间为 0.054s,基本与不用函数时间一致,可见函数已经下推,且函数实际执行耗时也并不高。
欢迎大家多多试用性能强大,又支持强一致性分布式事务的南大通用GBase 8c~~