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

打印 上一主题 下一主题

主题 1022|帖子 1022|积分 3066

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
摘要:本文就针对因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语句可以下推。
预置条件
  1. CREATE TABLE t1(name text, id INT) DISTRIBUTE BY HASH(id);
复制代码
原始语句
  1. MERGE INTO t1 USING (
  2. SELECT *
  3. FROM (VALUES ('json', 1), ('sam', 2)) AS val(name, id)
  4. ) tmp ON (t1.id = tmp.id)
  5. WHEN MATCHED THEN
  6. UPDATE SET t1.name = tmp.name
  7. WHEN NOT MATCHED THEN
  8. INSERT (name, id) VALUES(tmp.name, tmp.id);
复制代码
SQL语句不下推,导致执行低效
  1. postgres=# EXPLAIN VERBOSE MERGE INTO t1 USING (
  2. postgres(#     SELECT *
  3. postgres(#     FROM (VALUES ('json', 1), ('sam', 2)) AS val(name, id)
  4. postgres(# ) tmp ON (t1.id = tmp.id)
  5. postgres-# WHEN MATCHED THEN
  6. postgres-#     UPDATE SET t1.name = tmp.name
  7. postgres-# WHEN NOT MATCHED THEN
  8. postgres-#     INSERT (name, id) VALUES(tmp.name, tmp.id);
  9.                                                                             QUERY PLAN
  10. -------------------------------------------------------------------------------------------------------------------------------------------------------------------
  11.   id |                       operation                       | E-rows | E-distinct | E-width | E-costs
  12. ----+-------------------------------------------------------+--------+------------+---------+---------
  13. 1 | -> Merge on public.t1                                | 2 | | 54 | 0.08
  14. 2 | ->  Nested Loop Left Join (3, 4)                   | 2 | | 54 | 0.08
  15. 3 | -> Values Scan on "*VALUES*" | 2 | | 36 | 0.03
  16. 4 | -> Data Node Scan on t1 "_REMOTE_TABLE_QUERY_" | 2 | | 18 | 0.00
  17. SQL Diagnostic Information
  18. ------------------------------------------------------------
  19. SQL is not plan-shipping
  20.          reason: Type of Record in non-real table can not be shipped
  21.    Predicate Information (identified by plan id)
  22. -------------------------------------------------
  23. 1 --Merge on public.t1
  24.          Node expr: : $10
  25. 2 --Nested Loop Left Join (3, 4)
  26. Join Filter: (t1.id = "*VALUES*".column2)
  27. Targetlist Information (identified by plan id)
  28. -----------------------------------------------------------------------------------------------------------------------------------------------------------------
  29. 1 --Merge on public.t1
  30.          Node/s: All datanodes
  31.          Remote query: UPDATE ONLY public.t1 SET name = $7, id = $8 WHERE t1.ctid = $5 AND t1.xc_node_id = $6
  32.          Node/s: All datanodes
  33.          Remote query: INSERT INTO public.t1 (name, id) VALUES ($9, $10)
  34. 2 --Nested Loop Left Join (3, 4)
  35.          Output: "*VALUES*".column1, "*VALUES*".column2, t1.name, t1.id, t1.ctid, t1.xc_node_id, "*VALUES*".column1, t1.id, "*VALUES*".column1, "*VALUES*".column2
  36. 3 --Values Scan on "*VALUES*"
  37.          Output: "*VALUES*".column1, "*VALUES*".column2
  38. 4 --Data Node Scan on t1 "_REMOTE_TABLE_QUERY_"
  39.          Output: t1.name, t1.id, t1.ctid, t1.xc_node_id
  40.          Node/s: All datanodes
  41.          Remote query: SELECT name, id, ctid, xc_node_id FROM ONLY public.t1 WHERE true
  42. ====== Query Summary =====
  43. --------------------------
  44. Parser runtime: 0.079 ms
  45. Planner runtime: 1.392 ms
  46. Unique SQL Id: 1657855173
  47. (40 rows)
复制代码
改写方案
  1. MERGE INTO t1 USING (
  2. WITH val(name, id) AS(
  3. VALUES ('json', 1), ('sam', 2)
  4.     )
  5. SELECT * FROM val
  6. ) tmp ON (t1.id = tmp.id)
  7. WHEN MATCHED THEN
  8. UPDATE SET t1.name = tmp.name
  9. WHEN NOT MATCHED THEN
  10. INSERT (name, id) VALUES(tmp.name, tmp.id);
复制代码
改写后下推
  1. postgres=# EXPLAIN VERBOSE MERGE INTO t1 USING (
  2. postgres(#     WITH val(name, id) AS(
  3. postgres(#         VALUES ('json', 1), ('sam', 2)
  4. postgres(#     )
  5. postgres(#     SELECT * FROM val
  6. postgres(# ) tmp ON (t1.id = tmp.id)
  7. postgres-# WHEN MATCHED THEN
  8. postgres-#     UPDATE SET t1.name = tmp.name
  9. postgres-# WHEN NOT MATCHED THEN
  10. postgres-#     INSERT (name, id) VALUES(tmp.name, tmp.id);
  11.                                                                       QUERY PLAN
  12. ------------------------------------------------------------------------------------------------------------------------------------------------------
  13.   id |                  operation                   | E-rows | E-distinct | E-memory | E-width | E-costs
  14. ----+----------------------------------------------+--------+------------+----------+---------+---------
  15. 1 | ->  Streaming (type: GATHER)                 | 1 | | | 54 | 1.56
  16. 2 | -> Merge on public.t1                    | 2 | | | 54 | 1.15
  17. 3 | ->  Streaming(type: REDISTRIBUTE)      | 2 | | 2MB      | 54 | 1.15
  18. 4 | ->  Nested Loop Left Join (5, 7)    | 2 | | 1MB      | 54 | 1.11
  19. 5 | ->  Subquery Scan on tmp | 2 | | 1MB      | 36 | 0.08
  20. 6 | -> Values Scan on "*VALUES*" | 24 | | 1MB      | 36 | 0.03
  21. 7 | ->  Seq Scan on public.t1        | 2 | | 1MB      | 18 | 1.01
  22. Predicate Information (identified by plan id)
  23. ---------------------------------------------
  24. 4 --Nested Loop Left Join (5, 7)
  25. Join Filter: (t1.id = tmp.id)
  26. 5 --Subquery Scan on tmp
  27.          Filter: (Hash By tmp.id)
  28. Targetlist Information (identified by plan id)
  29. ----------------------------------------------------------------------------------------------------------------------------------------------------
  30. 1 --Streaming (type: GATHER)
  31.          Node/s: All datanodes
  32. 3 --Streaming(type: REDISTRIBUTE)
  33.          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)
  34.          Distribute Key: (CASE WHEN (t1.ctid IS NULL) THEN tmp.id ELSE t1.id END)
  35.          Spawn on: All datanodes
  36.          Consumer Nodes: All datanodes
  37. 4 --Nested Loop Left Join (5, 7)
  38.          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
  39. 5 --Subquery Scan on tmp
  40.          Output: tmp.name, tmp.id
  41. 6 --Values Scan on "*VALUES*"
  42.          Output: "*VALUES*".column1, "*VALUES*".column2
  43. 7 --Seq Scan on public.t1
  44.          Output: t1.name, t1.id, t1.ctid, t1.xc_node_id
  45.          Distribute Key: t1.id
  46. ====== Query Summary =====
  47. -------------------------------
  48. System available mem: 3112960KB
  49. Query Max mem: 3112960KB
  50. Query estimated mem: 6336KB
  51. Parser runtime: 0.107 ms
  52. Planner runtime: 1.185 ms
  53. Unique SQL Id: 780461632
  54. (44 rows)
复制代码
 
点击关注,第一时间了解华为云新鲜技术~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

没腿的鸟

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表