首页 > 其他分享 >UNION和GROUP BY连用 导致的无法谓词推入问题

UNION和GROUP BY连用 导致的无法谓词推入问题

时间:2023-11-03 17:04:54浏览次数:33  
标签:PREM GROUP UNION AGENT A1 视图 谓词 ID

问题概述

在分析客户环境的一条SQL时,发现了无法做谓词推入的现象。造成视图中的大表访问比较低效。故此对案例做了进一步分析及测试。以确定问题原因。

问题SQL:

SELECT SUM("A2"."PREM")
  FROM ((SELECT "A5"."AGENT_ID", SUM("A5"."PREM") "PREM"
           FROM QUERY_DES "A5"
          GROUP BY "A5"."AGENT_ID") 
          UNION ALL
        (SELECT "A4"."AGENT_ID", SUM("A4"."PREM") PREM
           FROM QUERY_OLD "A4"
          GROUP BY "A4"."AGENT_ID")) "A2",
       T_MAIN "A1"
 WHERE "A2"."AGENT_ID" = "A1"."AGENT_ID"
   AND "A1"."AGENT_CLASS" = 1
   AND "A1"."IDNUM" = 6;

SQL文本中包含通过UNION ALL合并的两个group by视图。视图与外部表通过AGENT_ID关联。

对应的执行计划如下:

UNION和GROUP BY连用 导致的无法谓词推入问题_执行计划

其中主要的耗时见标红部分。视图中访问了大量的中间结果,最后聚合后与外部表关联。为此创建关联条件列索引。

create index IDX_QUERYDES_AGENT on QUERY_DES(AGENT_ID,PREM);

create index IDX_QUERYOLD_AGENT on QUERY_OLD(AGENT_ID,PREM);

这里奇怪的是,外部T_MAIN只有一行记录。且存在关联条件索引时,我们希望能将关联条件推入到视图内部,这样可以一定程度上降低视图中表访问的中间结果,来提升访问的效率。而本例中显然没有成功。

这里看到是一体机环境,才能达到1秒左右的执行时间,如果是传统的X86环境,上述大表的全表扫其执行效率明显会很差。

问题分析

这里我们期望看到的是谓词推入技术。而实际事与愿违,不论如何添加hint,都无法推入关联条件到A2视图内。总是通过全表扫描访问视图中的大表。造成性能问题。对比谓词推入的条件:

UNION和GROUP BY连用 导致的无法谓词推入问题_union_02

可以看到是满足视图中包含UNION/UNION ALL的。只是唯一要注意的是UNION ALL两部分都是单独的GROUP BY结构。是否是这里的原因,导致无法继续推入到视图内部表的呢?

这里分析10053事件,这里看到连接谓词推入被跳过,基本确定与GROUP BY代码块有关。

UNION和GROUP BY连用 导致的无法谓词推入问题_union_03

而视图合并CVM也是更不会考虑。

UNION和GROUP BY连用 导致的无法谓词推入问题_执行效率_04

因此这里的UNION和GROUP BY连用,没有太有效的查询转换手段可以改善效率。

下面对SQL做一定程度的改写测试:

1. 去掉GROUP BY聚合

首先分析语句含义,GROUP BY只是为了获取每个AGENT_ID聚合后的SUM(PREM)值,而最外层也仅是对关联后的SUM(PREM)在做一次聚合。因此这里分析内部的SUM聚合完全就是可以省去的。去掉UNION ALL两部分的GROUP BY聚合。改写如下:


SELECT SUM("A2"."PREM")
  FROM ((SELECT "A5"."AGENT_ID", "A5"."PREM" FROM QUERY_DES "A5")
        UNION ALL
        (SELECT "A4"."AGENT_ID", "A4"."PREM" FROM QUERY_OLD "A4")) "A2",
       T_MAIN "A1"
 WHERE "A2"."AGENT_ID" = "A1"."AGENT_ID"
   AND "A1"."AGENT_CLASS" = 1
   AND "A1"."IDNUM" = 6;

针对本条查询的场景,完全可以等价的改写为上述写法。省去内层不必要的聚合的。

改写后的执行计划如下:

UNION和GROUP BY连用 导致的无法谓词推入问题_执行效率_05

调整为了上面的UNION ALL写法,外层条件顺利推入到视图内部。通过关联条件降低了内层表访问的中间结果。执行效率有了较大改善。

2.与内层GROUP BY关联后再UNION

上一小节的改法,受到很多限制。只有本案例相对特殊的情况才能省去内部聚合。更多的情况内部聚合无法拆开。因此更为广泛的改法是将外部表分别与内部两个GROUP BY视图关联,最后再UNION合并。


SELECT SUM("PREM")
  from (select "A1"."AGENT_ID", a2.PREM
          FROM (SELECT "A5"."AGENT_ID", SUM("A5"."PREM") "PREM"
                  FROM QUERY_DES "A5"
                 GROUP BY "A5"."AGENT_ID") "A2",
               T_MAIN "A1"
         WHERE "A2"."AGENT_ID" = "A1"."AGENT_ID"
           AND "A1"."AGENT_CLASS" = 1
           AND "A1"."IDNUM" = 6
        union all
        select "A1"."AGENT_ID", a2.PREM
          FROM (SELECT "A4"."AGENT_ID", SUM("A4"."PREM") PREM
                  FROM QUERY_OLD "A4"
                 GROUP BY "A4"."AGENT_ID") "A2",
               T_MAIN "A1"
         WHERE "A2"."AGENT_ID" = "A1"."AGENT_ID"
           AND "A1"."AGENT_CLASS" = 1
           AND "A1"."IDNUM" = 6);

这样调整后,是利用了谓词推入条件的“视图定义中包含GROUP BY”。UNION后在外层求和与原始查询等价。

调整后的执行计划:

UNION和GROUP BY连用 导致的无法谓词推入问题_union_06

调整后,相当于两部分满足谓词推入的场景。优化器分别对两部分GROUP BY应用了谓词推入技术。传入关联条件以降低视图中的数据访问量,提升查询效率。

除此之外,GROUP BY视图也是满足复杂视图合并的场景的。因此本案例还可以有更多的查询转换手段。复杂视图合并。


SELECT SUM("PREM")
  from (select "A1"."AGENT_ID", a2.PREM
          FROM (SELECT /*+ merge */
                 "A5"."AGENT_ID", SUM("A5"."PREM") "PREM"
                  FROM QUERY_DES "A5"
                 GROUP BY "A5"."AGENT_ID") "A2",
               T_MAIN "A1"
         WHERE "A2"."AGENT_ID" = "A1"."AGENT_ID"
           AND "A1"."AGENT_CLASS" = 1
           AND "A1"."IDNUM" = 6
        union all
        select "A1"."AGENT_ID", a2.PREM
          FROM (SELECT /*+ merge */
                 "A4"."AGENT_ID", SUM("A4"."PREM") PREM
                  FROM QUERY_OLD "A4"
                 GROUP BY "A4"."AGENT_ID") "A2",
               T_MAIN "A1"
         WHERE "A2"."AGENT_ID" = "A1"."AGENT_ID"
           AND "A1"."AGENT_CLASS" = 1
           AND "A1"."IDNUM" = 6);

利用hint实现GROUP BY视图合并。调整后执行计划如下:

UNION和GROUP BY连用 导致的无法谓词推入问题_执行计划_07

这样的写法还可以有视图合并手段可以选择,统一应用了关联条件实现内层表的过滤,提升了执行效率。

解决方案及总结

通过上一章节分析,针对UNION和GROUP BY视图连用的情况。无论是谓词推入还是视图合并,都无法进行。因此就需要一定程度的改写。

而我们分析:更有效的改写方法为通过外层表与内层视图关联后在UNION的方式。好处如下:

没有太多写法限制。不论最外层对聚合后的列做何种写法,都可以应用这种改写方式。

2.改写后性能更好。拆开后再UNION是先应用关联条件后立刻聚合。缩减数据量的同时执行效率更好。优于UNION两部分数据最后再聚合的方式。

3.有更多的查询转换手段。有视图合并和谓词推入两种转换手段。当不满足某一条件时还可以尝试另一种查询转换手段。更好的保证执行效率。

很多时候的无法谓词推入问题都与这类情况有关,可以利用外层表与内层视图关联后在UNION的方式来改写。还可以结合CTE写法(MATERIALIZE/INLINE),实现简化代码和提升性能的不同需求。

标签:PREM,GROUP,UNION,AGENT,A1,视图,谓词,ID
From: https://blog.51cto.com/u_13482808/8172855

相关文章

  • Hive / ClickHouse 行转列函数 collect_set() / groupUniqArray() 入门
    Hive/ClickHouse行转列函数collect_set()/groupUniqArray()入门在数据处理和分析中,我们经常会遇到需要将一行数据转换为多列的情况。在Hive和ClickHouse中,可以使用collect_set()和groupUniqArray()函数来实现行转列操作。collect_set()1.功能说明collect_set()函......
  • ELIC: Efficient Learned Image Compression with Unevenly Grouped Space-Channel Co
    abstruct\(\quad\)受能量压缩表现的启发,提出了不均匀通道情况自适应编码.结合不均匀分组模型和现有上下文模型,获得一种空间通道上下文自适应模型,来提高编码性能,而不影响其运行时间。\(\quad\)这种模型支持预览解码和渐进解码。introduction学习图像压缩中最重要的技术联合前......
  • Java 通过collectors.groupingBy根据某个字段统计
    要使用Collectors.groupingBy根据某个字段统计,你可以通过提供一个函数来指定分组的条件。假设你有一个包含Person对象的列表,每个对象都有age字段表示年龄,你想要根据年龄分组,并统计每个年龄组的人数。以下是一个使用Collectors.groupingBy的示例代码:importjava.util.Arrays;imp......
  • Java 使用`Collectors.groupingBy`计算百分比
    要使用Collectors.groupingBy计算百分比,你需要先对数据进行分组,然后计算每个组内元素的百分比。假设你有一个包含整数的列表,你想要按照它们的奇偶性进行分组,并计算每个组内元素的百分比。以下是一个使用Collectors.groupingBy和自定义收集器的示例代码:importjava.util.Arrays;......
  • 解决MYSQL查询报错 Expression #4 of SELECT list is not in GROUP BY clause and con
    原因:在MySQL5.7.5后,默认开启了ONLY_FULL_GROUP_BY,所以导致了之前的一些SQL无法正常执行,其实,是我们的SQL不规范造成的,因为groupby之后,返回的一些数据是不确定的,所以才会出现这个错误。执行下面的命令后,重启你的代码,就可以了selectversion(),@@sql_mode;SETsql_mode=(SELECTRE......
  • SharePoint 2019开发:如何通过脚本来变更SharePoint Group的 Permission Level
    Blog链接:https://blog.51cto.com/13969817很多企业出于安全管理需要,ITadmin需要根据SecurityPolicy或者审计要求定期批量的修改SharePoint权限,比如添加或者删除某个用户,或者更换某个Group的Permissionlevel等等,如果单纯的修改一个网站,那么我们可以直接到SiteSettings的Permiss......
  • 十一、LINQ基础—GroupBy子句
    一、简介group子句返回一个IGrouping(TKey,Telement)对象序列,编译时,group子句被转换成对GroupBy方法的调用。二、案例案例一:根据首字母分组,并打印到控制台//数据源string[]fruits={"apple","banana","peach","orange","melon","lemon"};//分组查询的查询语句......
  • EF Core无法翻译groupby等子查询
    烦人的表达式转化错误varquery1=emps.Grouby(v=>v.DeptId).Select(g=>new{DeptId=g.Key,Salary=g.Max(x=>x.Salary);varresult=fromdindeptsjoinqinquery1ond.Idequalsq.DeptIdselectnew{d.Name,q.Salary};上面代码运行起......
  • a-checkbox-group的用法2
    有时候在项目中,一个复选框组中,选中某个复选框都要进行一定的操作,如果不想使用整体的change事件,可以在单个的checkbox中定义change事件,比如如下代码:<a-checkbox-groupv-model="checkedList"><a-row:gutter="24"><a-col:span="6"v-for="{value,l......
  • MapReduce自定义GroupingComparator
    需求:有如下订单明细数据0000001 01 222.80000002 06 722.40000001 05 25.80000003 01 222.80000003 01 33.80000002 03 522.80000002 04 122.4第一列是订单编号,第二列是商品id,第三列是商品金额,列与列之间用制表符分隔。现在需要求出每一个订单中最贵的商品。思路:将订单id和商......