zoukankan      html  css  js  c++  java
  • 【Oracle】求同组最值(找每个部门最高薪水员工),分析函数相对于自联结(自连接)的优势

    有这么一个表:

    create table emp3(
        id number(8),
        name nvarchar2(20),
        deptname nvarchar2(20),
        salary number(6),
        primary key(id)
    );

    可以这样充值:

    declare 
       d integer;
       salary integer;
    begin
    for i in 1..1000000 loop
        d:=dbms_random.value(1,5);
        salary:=dbms_random.value(3000,99999);
    
        insert into emp3 values(i,
                    dbms_random.string('*',dbms_random.value(6,20)),
            decode(d,1,'销售',2,'售后',3,'研发',4,'市场',5,'管理'),
                    salary);
    end loop;
    
    commit;
    
    end;
    /

    好了,需求出来了:求每个部门薪水最高的员工。

    实现方式一:自连接(自联结)

    select * from emp3 a
    where a.salary=(select max(salary) from emp3 b where b.deptname=a.deptname)
    order by deptname

    执行效果:

    SQL> select * from emp3 a
      2  where a.salary=(select max(salary) from emp3 b where b.deptname=a.deptname)
      3  order by deptname;
    
            ID NAME                                     DEPTNAME                                     SALARY
    ---------- ---------------------------------------- ---------------------------------------- ----------
         90705 OIYXDGPGFLBCOE                           售后                                          99999
        382001 RSTFZVMJ                                 市场                                          99998
        891150 YAEBSBDXQTMV                             研发                                          99999
        182816 GBPKFQXGZLEHODVPR                        研发                                          99999
        214175 MEPMYZ                                   研发                                          99999
         42985 ABDXGRG                                  管理                                          99999
        953733 MITUNVMEIRUDZ                            销售                                          99999
    
    已选择 7 行。

    解释计划:

    explain plan for select * from emp3 a
    where a.salary=(select max(salary) from emp3 b where b.deptname=a.deptname)
    order by deptname;
    
    select * from table(dbms_xplan.display)
    
    SQL> explain plan for select * from emp3 a
      2  where a.salary=(select max(salary) from emp3 b where b.deptname=a.deptname)
      3  order by deptname;
    
    已解释。
    
    SQL> select * from table(dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------------------------------------------------------------------------
    Plan hash value: 956464727
    
    -----------------------------------------------------------------------------------------
    | Id  | Operation             | Name    | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
    -----------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT      |         |  1651K|   165M|       | 25606   (1)| 00:00:02 |
    |   1 |  MERGE JOIN           |         |  1651K|   165M|       | 25606   (1)| 00:00:02 |
    |   2 |   SORT JOIN           |         |   849K|    28M|    71M|  9777   (2)| 00:00:01 |
    |   3 |    VIEW               | VW_SQ_1 |   849K|    28M|       |  1849   (5)| 00:00:01 |
    |   4 |     HASH GROUP BY     |         |   849K|    28M|       |  1849   (5)| 00:00:01 |
    |   5 |      TABLE ACCESS FULL| EMP3    |   849K|    28M|       |  1791   (1)| 00:00:01 |
    
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------------------------------------------------------------------------
    |*  6 |   SORT JOIN           |         |   849K|    56M|   136M| 15822   (1)| 00:00:01 |
    |   7 |    TABLE ACCESS FULL  | EMP3    |   849K|    56M|       |  1791   (1)| 00:00:01 |
    -----------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       6 - access("ITEM_1"="A"."DEPTNAME" AND "A"."SALARY"="MAX(SALARY)")
           filter("ITEM_1"="A"."DEPTNAME" AND "A"."SALARY"="MAX(SALARY)")
    
    Note
    
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------------------------------------------------------------------------
    -----
       - dynamic statistics used: dynamic sampling (level=2)
    
    已选择 24 行。

    实现方式二:使用max分析函数

    代码:

    select b.id,b.name,b.deptname,b.salary from 
    (select a.*,max(salary) over (partition by deptname) as max_salary from emp3 a ) b
    where b.salary=b.max_salary
    order by b.deptname

    效果:

    SQL> select b.id,b.name,b.deptname,b.salary from
      2  (select a.*,max(salary) over (partition by deptname) as max_salary from emp3 a ) b
      3  where b.salary=b.max_salary
      4  order by b.deptname;
    
            ID NAME                                     DEPTNAME                                     SALARY
    ---------- ---------------------------------------- ---------------------------------------- ----------
         90705 OIYXDGPGFLBCOE                           售后                                          99999
        382001 RSTFZVMJ                                 市场                                          99998
        182816 GBPKFQXGZLEHODVPR                        研发                                          99999
        214175 MEPMYZ                                   研发                                          99999
        891150 YAEBSBDXQTMV                             研发                                          99999
         42985 ABDXGRG                                  管理                                          99999
        953733 MITUNVMEIRUDZ                            销售                                          99999
    
    已选择 7 行。

    解释计划:

    SQL> explain plan for select b.id,b.name,b.deptname,b.salary from
      2  (select a.*,max(salary) over (partition by deptname) as max_salary from emp3 a ) b
      3  where b.salary=b.max_salary
      4  order by b.deptname;
    
    已解释。
    
    SQL> select * from table(dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------------------------------------------------------------------------
    Plan hash value: 2505443670
    
    ------------------------------------------------------------------------------------
    | Id  | Operation           | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |      |   849K|    67M|       | 15822   (1)| 00:00:01 |
    |*  1 |  VIEW               |      |   849K|    67M|       | 15822   (1)| 00:00:01 |
    |   2 |   WINDOW SORT       |      |   849K|    56M|    68M| 15822   (1)| 00:00:01 |
    |   3 |    TABLE ACCESS FULL| EMP3 |   849K|    56M|       |  1791   (1)| 00:00:01 |
    ------------------------------------------------------------------------------------
    
    
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("B"."SALARY"="B"."MAX_SALARY")
    
    Note
    -----
       - dynamic statistics used: dynamic sampling (level=2)
    
    已选择 19 行。
    
    SQL>

    比较:

    从解释计划可以看出,max分析函数方案cost只是自连接方案的五分之三,前者全表访问一次,后者两次,前者明显胜出。

    END

  • 相关阅读:
    JAVA语言中冒号的用法
    Tamper Data 安装与使用
    HTTP协议缓存策略深入详解之ETAG妙用
    HTTP协议
    HTTP协议----ETag
    super 使用以及原理
    __slots__用法以及优化
    归并排序详解(Python | Java实现)
    周刷题第二期总结(Longest Substring Without Repeating Characters and Median of Two Sorted Arrays)
    周刷题第一期总结(two sum and two numbers)
  • 原文地址:https://www.cnblogs.com/heyang78/p/15374048.html
Copyright © 2011-2022 走看看