GaussDB(DWS)运维:导致SQL执行不下推的改写方案

gaussdb,dws,导致,sql,执行,不下,改写,方案 · 浏览次数 : 79

小编点评

## 改写的SQL语句 ```sql 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.nameWHEN NOT MATCHED THEN INSERT (name, id) VALUES(tmp.name, tmp.id); ``` **修改说明:** * 使用 WITH 语句定义了一个名为 `val` 的子查询,该子查询返回一个包含 `name` 和 `id` 的二维数组。 * 更改 `SELECT *` 为 `SELECT name, id`. * 使用 `WHERE` 子句进一步筛选匹配结果。 * 使用 `SET` 语句进行更新操作。 * 使用 `INSERT` 语句进行插入操作。 **其他优化:** * 可以使用索引来加速匹配过程。 * 可以使用批量操作来处理大量数据。

正文

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

GaussDB(DWS)运维:导致SQL执行不下推的改写方案

摘要:本文就针对因USING子句的书写方式可能导致MERGE INTO语句的执行不下推的场景,对USING子句的SQL语句进行改写一遍,整个SQL语句可以下推。 本文分享自华为云社区《GaussDB(DWS)运维 -- values子句做MERGE数据源导致SQL执行不下推的改写方案》,作者: 譡里

5个高并发导致数仓资源类报错分析

摘要:集群运行过程中,有时候会执行并发量比较高的业务场景,一些数据库没有为这种高并发作业配置合适的参数,会导致作业大量报错,这篇文章让你玩转并发作业。 本文分享自华为云社区《【玩转PB级数仓GaussDB(DWS)】在线运维 - 高并发导致资源类报错分析解决》,作者:323老四。 集群运行过程中,有

GaussDB(DWS)运维 :遇到truncate执行慢,怎么办?

摘要:truncate执行慢,耗时长达几十到几百秒,这可怎么破? 本文分享自华为云社区《GaussDB(DWS)运维 -- truncate慢》,作者: 譡里个檔。 【现象】truncate执行慢,耗时长达几十到几百秒 【根因】truncate表被查询表的DML语句阻塞 【方案】建议truncate

【数仓运维实践】关于GaussDB(DWS)单SQL磁盘空间管控

摘要:本文主要讲解数仓运维中遇到单SQL磁盘空间管控问题的解析和方案。 本文分享自华为云社区《GaussDB(DWS)运维 -- 单SQL磁盘空间管控》,作者: 譡里个檔。 【问题描述】 执行部分SQL语句时出现如下报错信息(具体数值可能因为配置有差异),本文针对根因和场景触发场景,确定触发此类问题

2个场景实例讲解GaussDB(DWS)基表统计信息估算不准的处理方案

摘要:通过2个实例场景讲解GaussDB(DWS)运维解决方案。 本文分享自华为云社区《GaussDB(DWS)运维 -- 基表统计信息估算不准的常见场景及处理方案》,作者:譡里个檔。 场景1:基表过滤字段存在的隐式类型时,基表行数估算偏小 这种场景绝大部分场景DWS能够处理,但是如果隐式类型转后的

数仓在线运维:如何进行在线增删CN?

摘要:集群运行过程中,根据集群的综合负载和业务接入情况进行分析:增加CN可以适当降低CPU消耗,增大接入连接数,分散CN节点业务压力,根据实际情况来识别是否要增加CN,如果是提升集群容量和扩展比能力,建议进行扩容操作。 本文分享自华为云社区《【玩转PB级数仓GaussDB(DWS)】在线运维-在线增

详解GaussDB(DWS)用户监控原理及应用

摘要:本文将聚焦于用户监控的原理及应用进行介绍。 本文分享自华为云社区《GaussDB(DWS)监控工具指南(二)用户级监控》,作者:幕后小黑爪 。 前言 资源监控是整个运维乃至整个产品生命周期重要的一环,事前及时语句发现故障,事后提供详实的数据用于追查定位问题。GaussDB(DWS)整个资源监控

数仓资源管控理论已掌握,是时候实战了

华为云GaussDB(DWS)技术布道师吕鹏博,针对GaussDB(DWS) 资源管控的原理和系统运维实践带来了精彩分享。

GaussDB(DWS)迁移实践丨row_number输出结果不一致

摘要:迁移前后结果集row_number字段值前后不一致,前在DWS上运行不一致。 本文分享自华为云社区《GaussDB(DWS)迁移 - oracle兼容 --row_number输出结果不一致》,作者:譡里个檔 。 【问题表现】 迁移前后结果集row_number字段值前后不一致,前在DWS上运

详解GaussDB(DWS)中的行执行引擎

本文分享自华为云社区《GaussDB(DWS)行执行引擎详解》,作者:yd_227398895。 1.前言 GaussDB(DWS)包含三大引擎,一是SQL执行引擎,用来解析用户输入的SQL语句,生成执行计划,供执行引擎来执行;二是执行引擎,其中包含了行执行引擎和列执行引擎,执行引擎即查询的执行者,