【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

原文地址:https://www.cnblogs.com/heyang78/p/15374048.html