【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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2019-10-06 [MySql]MySql中外键设置 以及Java/MyBatis程序对存在外键关联无法删除的规避