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)
GaussDB(DWS)运维:导致SQL执行不下推的改写方案的更多相关文章
- 【转】导致SQL执行慢的原因
索引对大数据的查询速度的提升是非常大的,Explain可以帮你分析SQL语句是否用到相关索引. 索引类似大学图书馆建书目索引,可以提高数据检索的效率,降低数据库的IO成本.MySQL在300万条记录左 ...
- 导致SQL执行慢的原因
索引对大数据的查询速度的提升是非常大的,Explain可以帮你分析SQL语句是否用到相关索引. 索引类似大学图书馆建书目索引,可以提高数据检索的效率,降低数据库的IO成本.MySQL在300万条记录左 ...
- 探索GaussDB(DWS)的过程化SQL语言能力
摘要:在当前GaussDB(DWS)的能力中主要支持两种过程化SQL语言,即基于PostgreSQL的PL/pgSQL以及基于Oracle的PL/SQL.本篇文章我们通过匿名块,函数,存储过程向大家介 ...
- hint不当索引,影响多表连接方式,最终导致SQL执行缓慢
需求:一个SQL执行特别慢,无法返回结果,需要进行优化,最终返回结果即可. 一.SQL分析 二.尝试执行,观测执行计划 三.修改SQL 四.问题总结 一.SQL分析 )SQL文本,执行时间,执行用户 ...
- sql serverDB运维实用sql大全
运维sql server的sql总结,包含阻塞语句.等待语句.某个时间段的sql性能查询等等常用sql语句 ##断开库的连接,记得修改库名 USE masterGOALTER DATABASE [DB ...
- 记一次,因表变量导致SQL执行效率变慢
场景 最近工作中,发现某同步JOB在执行中经常抛出SQL执行超时的问题,查看日志发现每次SQL执行的时间都是线性增长的,循环执行50次以后执行时间甚至超过了5分钟 JOB执行流程分析 首先,对于JO ...
- ELK学习笔记之F5 DNS可视化让DNS运维更安全更高效-F5 ELK可视化方案系列(3)
0x00 概述 此文力求比较详细的解释DNS可视化所能带来的场景意义,无论是运维.还是DNS安全.建议仔细看完下图之后的大篇文字段落,希望能引发您的一些思考. 在“F5利用Elastic stack( ...
- linux运维、架构之路-MHA高可用方案
一.软件介绍 MHA(master high availability)目前是MySQL高可用方面是一个相对成熟的解决方案.在切换过程中,mha能做到0-30s内自动完成数据库的 ...
- linux运维、架构之路-全网备份项目方案
一.项目需求说明 某公司有多台服务器,里面的数据很重要,如果磁盘坏了,数据就会丢失,所以公司要求把重要服务器数据备份以便出现问题时可以进行恢复,要求:每天晚上00点整在所有服务器上打包备份系统配置文件 ...
- 运维与开发的开车现场之MySQL5.7创建触发器报错解决过程
报错内容如下: ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds ...
随机推荐
- 在自定义Flink1.10 Sql Sink遇到的问题
1.org.apache.flink.table.api.TableException: Table sink does not implement a table schema. 问题:在Redis ...
- linux 第一节(基本命令)
RPM 红帽软件管理器,(源代码+安装规则打包) YUM 软件仓库yum源,打包了大量的软件. yum repolist all //列出所有仓库 ...
- Ajax 后台传值接收方法
$.ajax({ method: 'post', //数据类型 url: 'service.ashx?method=PostFile', //传输页面和页面方法 dataType: "jso ...
- STM32工程建立
STM32工程建立 对于用keil5建立stm32工程有两种方法,一种在学习过程中比较方便的建立方式:我们称为工程方式一,另一个便是在实际工程中用的最多,也最普遍,在实际过程中用的最多的,我们称为工程 ...
- Word技巧:ALT+X快捷键
Word技巧:ALT+X快捷键 在Word中输入数字,然后使用键盘快捷键「ALT + X」,即可快速生成一个文字图形. 部分数字的对比参照: 2564 ╤ 2582 ▂ 2600 2618 ☘ 256 ...
- 第一个知识点:import 和 export
//全部导入import people from './example' //有一种特殊情况,即允许你将整个模块当作单一对象进行导入//该模块的所有导出都会作为对象的属性存在import * as e ...
- vue上传证书
//队伍证书上传 getFile() { var that = this; // //1 创建formData let formData = new FormData(); // //2 添加数据,k ...
- pt-table-check和pt-table-sync实践
如果主库使用非默认端口,--recursion-method默认值为hosts,这时如果从库没有配置report_host参数(注意该参数缺点),则pt-table-checksum无法自动检测到从库 ...
- Python测试——安装篇总结
测试用到的工具自己知道的有: 写脚本类:sublime ,PyCharm,Eclipse+PyDev,目前我知道的只有这么多,大家知道的肯定还有很多,欢迎留言哈 录制脚本类:火狐自带的seleniu ...
- vector的使用方法
vector是STL容器的可变长度数组.可变长度数组的头文件是<vector>,有以下常见的使用方法: 1.vector<int> v(N,i):建立一个可变长度数组v,内部元 ...