GaussDB(DWS)运维:导致SQL执行不下推的改写方案
摘要:本文就针对因USING子句的书写方式可能导致MERGE INTO语句的执行不下推的场景,对USING子句的SQL语句进行改写一遍,整个SQL语句可以下推。
本文分享自华为云社区《GaussDB(DWS)运维 -- values子句做MERGE数据源导致SQL执行不下推的改写方案》,作者: 譡里个檔。
现网做实时接入的时候,有的时候会使用MERGE INTO语句实现类似UPSERT的功能。这种场景下MERGE INTO语句的USING部分的数据位VALUES子句,为了后续的SQL语句中描述方便,需要对VALUES子句的输出命名别名。USING子句的书写方式可能导致MERGE INTO语句的执行不下推,本文就针对因此导致的不下推的场景,对USING子句的SQL语句进行改写一遍,整个SQL语句可以下推。
预置条件
CREATE TABLE t1(name text, id INT) DISTRIBUTE BY HASH(id);
原始语句
MERGE INTO t1 USING (
SELECT *
FROM (VALUES ('json', 1), ('sam', 2)) AS val(name, id)
) tmp ON (t1.id = tmp.id)
WHEN MATCHED THEN
UPDATE SET t1.name = tmp.name
WHEN NOT MATCHED THEN
INSERT (name, id) VALUES(tmp.name, tmp.id);
SQL语句不下推,导致执行低效
postgres=# EXPLAIN VERBOSE MERGE INTO t1 USING (
postgres(# SELECT *
postgres(# FROM (VALUES ('json', 1), ('sam', 2)) AS val(name, id)
postgres(# ) tmp ON (t1.id = tmp.id)
postgres-# WHEN MATCHED THEN
postgres-# UPDATE SET t1.name = tmp.name
postgres-# WHEN NOT MATCHED THEN
postgres-# INSERT (name, id) VALUES(tmp.name, tmp.id);
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
id | operation | E-rows | E-distinct | E-width | E-costs
----+-------------------------------------------------------+--------+------------+---------+---------
1 | -> Merge on public.t1 | 2 | | 54 | 0.08
2 | -> Nested Loop Left Join (3, 4) | 2 | | 54 | 0.08
3 | -> Values Scan on "*VALUES*" | 2 | | 36 | 0.03
4 | -> Data Node Scan on t1 "_REMOTE_TABLE_QUERY_" | 2 | | 18 | 0.00
SQL Diagnostic Information
------------------------------------------------------------
SQL is not plan-shipping
reason: Type of Record in non-real table can not be shipped
Predicate Information (identified by plan id)
-------------------------------------------------
1 --Merge on public.t1
Node expr: : $10
2 --Nested Loop Left Join (3, 4)
Join Filter: (t1.id = "*VALUES*".column2)
Targetlist Information (identified by plan id)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
1 --Merge on public.t1
Node/s: All datanodes
Remote query: UPDATE ONLY public.t1 SET name = $7, id = $8 WHERE t1.ctid = $5 AND t1.xc_node_id = $6
Node/s: All datanodes
Remote query: INSERT INTO public.t1 (name, id) VALUES ($9, $10)
2 --Nested Loop Left Join (3, 4)
Output: "*VALUES*".column1, "*VALUES*".column2, t1.name, t1.id, t1.ctid, t1.xc_node_id, "*VALUES*".column1, t1.id, "*VALUES*".column1, "*VALUES*".column2
3 --Values Scan on "*VALUES*"
Output: "*VALUES*".column1, "*VALUES*".column2
4 --Data Node Scan on t1 "_REMOTE_TABLE_QUERY_"
Output: t1.name, t1.id, t1.ctid, t1.xc_node_id
Node/s: All datanodes
Remote query: SELECT name, id, ctid, xc_node_id FROM ONLY public.t1 WHERE true
====== Query Summary =====
--------------------------
Parser runtime: 0.079 ms
Planner runtime: 1.392 ms
Unique SQL Id: 1657855173
(40 rows)
改写方案
MERGE INTO t1 USING (
WITH val(name, id) AS(
VALUES ('json', 1), ('sam', 2)
)
SELECT * FROM val
) tmp ON (t1.id = tmp.id)
WHEN MATCHED THEN
UPDATE SET t1.name = tmp.name
WHEN NOT MATCHED THEN
INSERT (name, id) VALUES(tmp.name, tmp.id);
改写后下推
postgres=# EXPLAIN VERBOSE MERGE INTO t1 USING (
postgres(# WITH val(name, id) AS(
postgres(# VALUES ('json', 1), ('sam', 2)
postgres(# )
postgres(# SELECT * FROM val
postgres(# ) tmp ON (t1.id = tmp.id)
postgres-# WHEN MATCHED THEN
postgres-# UPDATE SET t1.name = tmp.name
postgres-# WHEN NOT MATCHED THEN
postgres-# INSERT (name, id) VALUES(tmp.name, tmp.id);
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------
id | operation | E-rows | E-distinct | E-memory | E-width | E-costs
----+----------------------------------------------+--------+------------+----------+---------+---------
1 | -> Streaming (type: GATHER) | 1 | | | 54 | 1.56
2 | -> Merge on public.t1 | 2 | | | 54 | 1.15
3 | -> Streaming(type: REDISTRIBUTE) | 2 | | 2MB | 54 | 1.15
4 | -> Nested Loop Left Join (5, 7) | 2 | | 1MB | 54 | 1.11
5 | -> Subquery Scan on tmp | 2 | | 1MB | 36 | 0.08
6 | -> Values Scan on "*VALUES*" | 24 | | 1MB | 36 | 0.03
7 | -> Seq Scan on public.t1 | 2 | | 1MB | 18 | 1.01
Predicate Information (identified by plan id)
---------------------------------------------
4 --Nested Loop Left Join (5, 7)
Join Filter: (t1.id = tmp.id)
5 --Subquery Scan on tmp
Filter: (Hash By tmp.id)
Targetlist Information (identified by plan id)
----------------------------------------------------------------------------------------------------------------------------------------------------
1 --Streaming (type: GATHER)
Node/s: All datanodes
3 --Streaming(type: REDISTRIBUTE)
Output: tmp.name, tmp.id, t1.name, t1.id, t1.ctid, t1.xc_node_id, tmp.name, tmp.id, (CASE WHEN (t1.ctid IS NULL) THEN tmp.id ELSE t1.id END)
Distribute Key: (CASE WHEN (t1.ctid IS NULL) THEN tmp.id ELSE t1.id END)
Spawn on: All datanodes
Consumer Nodes: All datanodes
4 --Nested Loop Left Join (5, 7)
Output: tmp.name, tmp.id, t1.name, t1.id, t1.ctid, t1.xc_node_id, tmp.name, tmp.id, CASE WHEN (t1.ctid IS NULL) THEN tmp.id ELSE t1.id END
5 --Subquery Scan on tmp
Output: tmp.name, tmp.id
6 --Values Scan on "*VALUES*"
Output: "*VALUES*".column1, "*VALUES*".column2
7 --Seq Scan on public.t1
Output: t1.name, t1.id, t1.ctid, t1.xc_node_id
Distribute Key: t1.id
====== Query Summary =====
-------------------------------
System available mem: 3112960KB
Query Max mem: 3112960KB
Query estimated mem: 6336KB
Parser runtime: 0.107 ms
Planner runtime: 1.185 ms
Unique SQL Id: 780461632
(44 rows)

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
喜马拉雅基于阿里云机器学习平台PAI-HybridBackend的深度学习模型训练优化实践
喜马拉雅作者:李超、陶云、许晨昱、胡文俊、张争光、赵云鹏、张玉静 喜马拉雅AI云借助阿里云提供的HybridBackend开源框架,实现了其推荐模型在 GPU 上的高效训练。 业务介绍 推荐场景是喜马拉雅app的重要应用之一,它广泛应用于热点、猜你喜欢、私人FM、首页信息流、发现页推荐、每日必听等模块。这些模块都依赖于喜马拉雅AI云,这是一套从数据、特征、模型到服务的全流程一站式算法工具平台。 推荐服务的一个核心诉求是能快速捕捉和反映用户不断变化的兴趣和当前热点,这就要求模型能在短时间内,以可控的成本完成对海量用户数据的训练。使用GPU等高性能硬件来加速模型训练已经成为CV, NLP等领域的行业标准;在使用稀疏训练数据的推荐场景下,国内外的各大厂商也在积极转向使用高性能GPU来替代传统的CPU训练集群,以提升训练的效率。 喜马拉雅AI云借助阿里云机器学习平台PAI的开源框架HybridBackend(以下简称HybridBackend),实现了其推荐模型在 GPU 上的高效训练。在加速训练的同时, HybridBackend 框架高度易用,帮助其算法团队提升了开发效率。 问题与挑战 随...
-
下一篇
Android性能优化-ListView自适应性能问题
作者:京东物流 张振勇 ListView是Android中最常用的视图之一,使用的频率仅仅次于几大基础布局,虽然由于使用性和扩展性等原因备受争议,且尽管后来出现了RecyclerView的替代方案,但是ListView仍然广泛地使用在我们的项目中。 自从ListView出道至今,已经不知道衍生出了多少问题,然而很多人只关心功能功能的实现,却极少关注ListView过度调用导致的性能问题。在实际项目中,即使你正确使用了ViewHolder机制来优化ListView性能,但是在某些场景下依然会感觉卡顿严重,到底是什么原因导致的呢,我们来分析下 1 问题演示 很多时候,我们在使用ListView的时候,都是随手写上一个layout_height=”wrap_content”或者layout_height=”match_parent”,非常常规的写法,乍一看,并没有什么问题,尤其是功能实现上也是无可挑剔。 然而,就是layout_height=”wrap_content”这个属性是导致严重的性能问题的根源,下面以一个简单的例子说明一下: 布局如上,接下来,假设ListView一共有5项,那么显...
相关文章
文章评论
共有0条评论来说两句吧...