摘要:本文就针对因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执行不下推的改写方案的更多相关文章

  1. 【转】导致SQL执行慢的原因

    索引对大数据的查询速度的提升是非常大的,Explain可以帮你分析SQL语句是否用到相关索引. 索引类似大学图书馆建书目索引,可以提高数据检索的效率,降低数据库的IO成本.MySQL在300万条记录左 ...

  2. 导致SQL执行慢的原因

    索引对大数据的查询速度的提升是非常大的,Explain可以帮你分析SQL语句是否用到相关索引. 索引类似大学图书馆建书目索引,可以提高数据检索的效率,降低数据库的IO成本.MySQL在300万条记录左 ...

  3. 探索GaussDB(DWS)的过程化SQL语言能力

    摘要:在当前GaussDB(DWS)的能力中主要支持两种过程化SQL语言,即基于PostgreSQL的PL/pgSQL以及基于Oracle的PL/SQL.本篇文章我们通过匿名块,函数,存储过程向大家介 ...

  4. hint不当索引,影响多表连接方式,最终导致SQL执行缓慢

    需求:一个SQL执行特别慢,无法返回结果,需要进行优化,最终返回结果即可. 一.SQL分析 二.尝试执行,观测执行计划 三.修改SQL 四.问题总结 一.SQL分析 )SQL文本,执行时间,执行用户 ...

  5. sql serverDB运维实用sql大全

    运维sql server的sql总结,包含阻塞语句.等待语句.某个时间段的sql性能查询等等常用sql语句 ##断开库的连接,记得修改库名 USE masterGOALTER DATABASE [DB ...

  6. 记一次,因表变量导致SQL执行效率变慢

    场景 最近工作中,发现某同步JOB在执行中经常抛出SQL执行超时的问题,查看日志发现每次SQL执行的时间都是线性增长的,循环执行50次以后执行时间甚至超过了5分钟 JOB执行流程分析  首先,对于JO ...

  7. ELK学习笔记之F5 DNS可视化让DNS运维更安全更高效-F5 ELK可视化方案系列(3)

    0x00 概述 此文力求比较详细的解释DNS可视化所能带来的场景意义,无论是运维.还是DNS安全.建议仔细看完下图之后的大篇文字段落,希望能引发您的一些思考. 在“F5利用Elastic stack( ...

  8. linux运维、架构之路-MHA高可用方案

    一.软件介绍          MHA(master high   availability)目前是MySQL高可用方面是一个相对成熟的解决方案.在切换过程中,mha能做到0-30s内自动完成数据库的 ...

  9. linux运维、架构之路-全网备份项目方案

    一.项目需求说明 某公司有多台服务器,里面的数据很重要,如果磁盘坏了,数据就会丢失,所以公司要求把重要服务器数据备份以便出现问题时可以进行恢复,要求:每天晚上00点整在所有服务器上打包备份系统配置文件 ...

  10. 运维与开发的开车现场之MySQL5.7创建触发器报错解决过程

    报错内容如下: ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds ...

随机推荐

  1. Kubernetes--创建Ingress资源

    创建Ingress资源 Ingress资源是基于HTTP虚拟主机或URL的转发规则,它在资源配置清单的spec字段中嵌套了rules.backend和tls等字段进行定义.下面的示例中定义了一个Ing ...

  2. nginx 工作流程

    NGINX 把http请求处理流程划分为11个阶段,逻辑细分,以模块为单位进行处理.各个阶段可以包含多个http模块,每个阶段以流水线的形式处理请求.这样的分层处理模式与计算机网络的7层模式类似,每个 ...

  3. Check If Binary Tree Is Completed

    Check if a given binary tree is completed. A complete binary tree is one in which every level of the ...

  4. vs2013如何添加扩展库函数

    本文仅针对C和C++ vs2013下载C/C++编译器后,能够包含常见的头文件,stdlib.h,stdio.h,math.h这些.如果有其他需求例如:调用GL/glfw32.h,freeglut.h ...

  5. cpu主频对网络传输性能的影响

    数据包长度是:2KB iperf的测试结果:3.2GHz的cpu能上40Gb/s, 2.1GHz的cpu只能到28Gb/s.

  6. Windows+svn +Jenkins+发布NetCore/VUE项目

    1. NetCore环境下载,注意是下载SDK,不是Runtime:https://dotnet.microsoft.com/download/dotnet-core?utm_source=getdo ...

  7. AX2012 查询后台数据库记录

    AX2012 自带的数据库查询功能比较慢(特别是查询删除的情况),有些业务可能需要频繁查询删除人和删除时间等,这种情况下还是用代码来查询比较快. 例: static void SysDataBaseL ...

  8. uniapp+vue3+ts

    1. 创建vue3的默认uniapp模板 2. npm init 创建package.json

  9. mybatis批量更新的几种方式和性能对比

    https://blog.csdn.net/csdnbeyoung/article/details/106258611

  10. vue+element 表格动态列添加点击事件与排序(/或者空值排最后)

    <template> <div> <el-table     ref="tableData"       :data="tableData& ...