[oracle/sql]求员工表中每个部门里薪水最高的员工,那种sql最优?

   2023-02-09 学习力0
核心提示:开始正题前,先把我的数据库环境列出:#类别版本1操作系统Win102数据库Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production3硬件环境T440p 下面进入正题有个员工表emp如下:CREATE TABLE emp(id NUMBER not null primary key,nam

开始正题前,先把我的数据库环境列出:

# 类别 版本
1 操作系统 Win10
2 数据库 Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
3 硬件环境 T440p

 

下面进入正题

有个员工表emp如下:

CREATE TABLE emp
(
    id NUMBER not null primary key,
    name NVARCHAR2(60) not null,
    salary NUMBER(6,0) NOT NULL,
    deptid NUMBER(2,0) not null
)

可以采用以下sql来填充数据:

Insert into emp
 select rownum,dbms_random.string('*',dbms_random.value(6,20)),dbms_random.value(0,50000),dbms_random.value(0,10) from dual
 connect by level<=10000
 order by dbms_random.random

可以采取下面sql来得到每个部门的最高薪水额,以便后面的分析(得出数据这是本机的结果,诸位因为随机数的原因一定不会和我一样):

SQL> select max(salary),deptid from emp
  2  group by deptid
  3  order by deptid;

MAX(SALARY)     DEPTID
----------- ----------
      49944          0
      49991          1
      49988          2
      49993          3
      49927          4
      49988          5
      49924          6
      49923          7
      49848          8
      49934          9
      49894         10

已选择11行。

已用时间:  00: 00: 00.01

有下面三种sql都能查询出每个部门薪水最高的员工的结果,它们是:

1.
select a.id,a.name,a.salary,a.deptid from emp a
where salary=(select max(salary) from emp b where a.deptid=b.deptid)
order by a.id

2.
select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp
                group by deptid
                ) e2
where e1.deptid=e2.deptid and e1.salary=e2.max_sal
order by e1.id

3.
select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e)
where salary=max_sal
order by id

 

我分别按执行时间消耗(取第二遍sql结果)和执行计划cost列出了一个对比表格如下:

# sql Time elapsed Cost
1
select a.id,a.name,a.salary,a.deptid from emp a
where salary=(select max(salary) from emp b where a.deptid=b.deptid)
order by a.id
00: 00: 00.03 41
2
select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp
                group by deptid
                ) e2
where e1.deptid=e2.deptid and e1.salary=e2.max_sal
order by e1.id
00: 00: 07.92 641
3
select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e)
where salary=max_sal
order by id
00: 00: 00.01 471

按时间消耗是3胜出,1紧随,2差一大截;按cost是1胜出,3和2差了一个数量级;按从执行感觉来说是1,3最快,体会不出差别,而2有明显的停顿。

我的结论是:因为时间消耗和感觉两者可以互相对证,因此是可信的,但执行计划给出的结论在3的身上与现实有明显差别,只好弃而不取。

这个示例证明,执行计划的cost不能单独拿来说明哪个sql更优,即使两者比较差一个数量级也不可贸然采信,它必须得到耗时和现实运行感觉的印证才行;反而耗时可行度很高,按我的经验可以单独采信。

附:耗时比较:

SQL> select a.id,a.name,a.salary,a.deptid from emp a
  2  where salary=(select max(salary) from emp b where a.deptid=b.deptid)
  3  order by a.id;

        ID NAME
        SALARY     DEPTID
---------- ------------------------------------------------------------------------------------------------------------------------ ---------- ----------
      1073 UGJURPQV
         49993          3
      1356 UPHXQELWTDBLFYRBSHSF
         49991          1
      2946 SGSJBCABNNQXGORWPO
         49924          6
      3111 PQMATSYLQNZR
         49848          8
      3516 CBXGAVDIHITQ
         49944          0
      6218 LPZAQPOKQSJNAMNTOT
         49923          7
      7874 LBQPRRDVXUQS
         49988          5
      9032 OPVFSDKNZ
         49988          2
      9329 XRNKOKCCUORV
         49934          9
      9437 WQDWBTNEKJJYFL
         49894         10
      9979 YLXJXJPRKKBXAQIE
         49927          4

已选择11行。

已用时间:  00: 00: 00.03

SQL> select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp
  2  group by deptid
  3  ) e2
  4  where e1.deptid=e2.deptid and e1.salary=e2.max_sal
  5  order by e1.id;

        ID NAME
        SALARY     DEPTID
---------- ------------------------------------------------------------------------------------------------------------------------ ---------- ----------
      1073 UGJURPQV
         49993          3
      1356 UPHXQELWTDBLFYRBSHSF
         49991          1
      2946 SGSJBCABNNQXGORWPO
         49924          6
      3111 PQMATSYLQNZR
         49848          8
      3516 CBXGAVDIHITQ
         49944          0
      6218 LPZAQPOKQSJNAMNTOT
         49923          7
      7874 LBQPRRDVXUQS
         49988          5
      9032 OPVFSDKNZ
         49988          2
      9329 XRNKOKCCUORV
         49934          9
      9437 WQDWBTNEKJJYFL
         49894         10
      9979 YLXJXJPRKKBXAQIE
         49927          4

已选择11行。

已用时间:  00: 00: 07.92

SQL> select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e)
  2  where salary=max_sal
  3  order by id;

        ID NAME
        SALARY     DEPTID
---------- ------------------------------------------------------------------------------------------------------------------------ ---------- ----------
      1073 UGJURPQV
         49993          3
      1356 UPHXQELWTDBLFYRBSHSF
         49991          1
      2946 SGSJBCABNNQXGORWPO
         49924          6
      3111 PQMATSYLQNZR
         49848          8
      3516 CBXGAVDIHITQ
         49944          0
      6218 LPZAQPOKQSJNAMNTOT
         49923          7
      7874 LBQPRRDVXUQS
         49988          5
      9032 OPVFSDKNZ
         49988          2
      9329 XRNKOKCCUORV
         49934          9
      9437 WQDWBTNEKJJYFL
         49894         10
      9979 YLXJXJPRKKBXAQIE
         49927          4

已选择11行。

已用时间:  00: 00: 00.01

执行计划比较:

SQL> select a.id,a.name,a.salary,a.deptid from emp a
  2  where salary=(select max(salary) from emp b where a.deptid=b.deptid)
  3  order by a.id;
已用时间:  00: 00: 00.00

执行计划
----------------------------------------------------------
Plan hash value: 1231226589

---------------------------------------------------------------------------------
| Id  | Operation             | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |         |     1 |   127 |    41   (8)| 00:00:01 |
|   1 |  SORT ORDER BY        |         |     1 |   127 |    41   (8)| 00:00:01 |
|*  2 |   HASH JOIN           |         |     1 |   127 |    40   (5)| 00:00:01 |
|   3 |    VIEW               | VW_SQ_1 |  9121 |   231K|    21  (10)| 00:00:01 |
|   4 |     HASH GROUP BY     |         |  9121 |   231K|    21  (10)| 00:00:01 |
|   5 |      TABLE ACCESS FULL| EMP     |  9121 |   231K|    19   (0)| 00:00:01 |
|   6 |    TABLE ACCESS FULL  | EMP     |  9121 |   899K|    19   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("SALARY"="MAX(SALARY)" AND "A"."DEPTID"="ITEM_1")

Note
-----
   - dynamic sampling used for this statement (level=2)
   
SQL> select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp
  2  group by deptid
  3  ) e2
  4  where e1.deptid=e2.deptid and e1.salary=e2.max_sal
  5  order by e1.id;
已用时间:  00: 00: 00.00

执行计划
----------------------------------------------------------
Plan hash value: 962461943

-----------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |  7562K|  1002M|   641  (95)| 00:00:08 |
|*  1 |  FILTER              |      |       |       |            |          |
|   2 |   SORT GROUP BY      |      |  7562K|  1002M|   641  (95)| 00:00:08 |
|*  3 |    HASH JOIN         |      |  7562K|  1002M|    92  (59)| 00:00:02 |
|   4 |     TABLE ACCESS FULL| EMP  |  9121 |   231K|    19   (0)| 00:00:01 |
|   5 |     TABLE ACCESS FULL| EMP  |  9121 |  1006K|    19   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("E1"."SALARY"=MAX("SALARY"))
   3 - access("E1"."DEPTID"="DEPTID")

Note
-----
   - dynamic sampling used for this statement (level=2)
   
SQL> select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e)
  2  where salary=max_sal
  3  order by id;
已用时间:  00: 00: 00.00

执行计划
----------------------------------------------------------
Plan hash value: 3418936035

-------------------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |  9121 |  1015K|       |   471   (1)| 00:00:06 |
|   1 |  SORT ORDER BY       |      |  9121 |  1015K|  1168K|   471   (1)| 00:00:06 |
|*  2 |   VIEW               |      |  9121 |  1015K|       |   234   (1)| 00:00:03 |
|   3 |    WINDOW SORT       |      |  9121 |   899K|  1056K|   234   (1)| 00:00:03 |
|   4 |     TABLE ACCESS FULL| EMP  |  9121 |   899K|       |    19   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("SALARY"="MAX_SAL")

Note
-----
   - dynamic sampling used for this statement (level=2)

2020年1月19日

参考资料:https://blog.csdn.net/paul_wei2008/article/details/19565509

2020-01-20补记,下面是在oracle12上执行的解释计划,取得第二遍结果,但结论,更让人迷糊了,这再次说明解释计划不能单独采信。

Oracle版本:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production PL/SQL Release 12.2.0.1.0 - Production "CORE 12.2.0.1.0 Production" TNS for Linux: Version 12.2.0.1.0 - Production NLSRTL Version 12.2.0.1.0 - Production #1 EXPLAIN PLAN FOR select a.id,a.name,a.salary,a.deptid from emp a where salary=(select max(salary) from emp b where a.deptid=b.deptid) order by a.id Plan hash value: 1231226589 --------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 11 | 605 | 40 (5)| 00:00:01 | | 1 | SORT ORDER BY | | 11 | 605 | 40 (5)| 00:00:01 | |* 2 | HASH JOIN | | 11 | 605 | 39 (3)| 00:00:01 | | 3 | VIEW | VW_SQ_1 | 11 | 176 | 20 (5)| 00:00:01 | | 4 | HASH GROUP BY | | 11 | 88 | 20 (5)| 00:00:01 | | 5 | TABLE ACCESS FULL| EMP | 10000 | 80000 | 19 (0)| 00:00:01 | | 6 | TABLE ACCESS FULL | EMP | 10000 | 380K| 19 (0)| 00:00:01 | --------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("SALARY"="MAX(SALARY)" AND "A"."DEPTID"="ITEM_1") #2 select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp group by deptid ) e2 where e1.deptid=e2.deptid and e1.salary=e2.max_sal order by e1.id Plan hash value: 2003893481 ------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 11 | 605 | 40 (5)| 00:00:01 | | 1 | SORT ORDER BY | | 11 | 605 | 40 (5)| 00:00:01 | |* 2 | HASH JOIN | | 11 | 605 | 39 (3)| 00:00:01 | | 3 | VIEW | | 11 | 176 | 20 (5)| 00:00:01 | | 4 | HASH GROUP BY | | 11 | 88 | 20 (5)| 00:00:01 | | 5 | TABLE ACCESS FULL| EMP | 10000 | 80000 | 19 (0)| 00:00:01 | | 6 | TABLE ACCESS FULL | EMP | 10000 | 380K| 19 (0)| 00:00:01 | ------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("E1"."DEPTID"="E2"."DEPTID" AND "E1"."SALARY"="E2"."MAX_SAL") #3 select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e) where salary=max_sal order by id Plan hash value: 3418936035 ------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 10000 | 1035K| | 365 (1)| 00:00:01 | | 1 | SORT ORDER BY | | 10000 | 1035K| 1192K| 365 (1)| 00:00:01 | |* 2 | VIEW | | 10000 | 1035K| | 121 (1)| 00:00:01 | | 3 | WINDOW SORT | | 10000 | 380K| 520K| 121 (1)| 00:00:01 | | 4 | TABLE ACCESS FULL| EMP | 10000 | 380K| | 19 (0)| 00:00:01 | ------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("SALARY"="MAX_SAL")

 

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • sql:mysql:函数:TIMESTAMPDIFF函数实现TimeStamp字段相减,求得时间差
    sql:mysql:函数:TIMESTAMPDIFF函数实现TimeS
     函数内指定是minute,则最终结果value值的单位是分钟,如果函数内指定为hours,则最终结果value值单位为小时。//UPLOAD_TIME 减去 CREATE_DTTM 求得时间差,以分钟数计时select avg(TIMESTAMPDIFF(MINUTE,CREATE_DTTM,UPLOAD_TIME)) value,LEFT(CREATE_DTTM
    03-08
  • 去重复的sql(Oracle) 去重复的英文
    1.利用group by 去重复2.可以利用下面的sql去重复,如下  1) select id,name,sex from (select a.*,row_number() over(partition by a.id,a.set order by name) su from test a ) where su=1  2)select id,name,sex from (select a.*,row_number() over(p
    02-10
  • Oracle SQL七次提速技巧
    以下SQL执行时间按序号递减。1,动态SQL,没有绑定变量,每次执行都做硬解析操作,占用较大的共享池空间,若共享池空间不足,会导致其他SQL语句的解析信息被挤出共享池。create or replace procedure proc1as beginfor i in 1..100000 loop    execute imme
    02-10
  • Oracle\SQL  Server等及其他基本语句写法
    Oracle\SQL Server等及其他基本语句写法
    Oracle\SQL  Server等及其他基本语句写法目录一.Excel相关 11.Excel中写脚本范例: 12.提取字节 23. 提取单元格内字符 24.VLOOKUP函数: 2二.SQL语句汇总 21.建表: 22.增 33.删 44.查 65.改 236.Alter的应用 24三.数据库备份与恢复脚本 261. Oracle: 2
    02-10
  • SQL ORACLE case when函数用法
    case when 用法(1)简单case函数:格式:  case 列名   when 条件值1 then 选项1  when 条件值1 then 选项2......  else 默认值 end例如:  select   case job_level  when '1' then '1111'  when '2' then '2222'   when '3' then '3333
    02-10
  • mysql下如何执行sql脚本 执行SQL脚本
    1.编写sql脚本,假设内容如下:  create database dearabao;  use dearabao;  create table niuzi (name varchar(20));  保存脚本文件,假设我把它保存在F盘的hello world目录下,于是该文件的路径为:F:\hello world\niuzi.sql2.执行sql脚本,可以有2种方法: 
    02-10
  • MySQL 5.7版本sql_mode=only_full_group_by问题
    用到GROUP BY 语句查询时com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'col_user_6.a.START_TIME' which is not functionally dependent on colu
    02-10
  • Oracle迁移到MySQL性能下降的注意点 oracle数据
    背景:最近有较多的客户系统由原来由Oracle改造到MySQL后出现了性能问题CPU 100%,或是后台的CRM系统复杂SQL在业务高峰的时候出现堆积导致业务故障。在我的记忆里面淘宝最初从Oracle迁移到MySQL期间也遇到了很多SQL的性能问题,记忆最为深刻的子查询,当初的
    02-10
  • ORACLE中通过SQL语句(alter table)来增加、删除
    1.添加字段:alter table  表名  add (字段  字段类型)  [ default  '输入默认值']  [null/not null]  ;2.添加备注:comment on column  库名.表名.字段名 is  '输入的备注';  如: 我要在ers_data库中  test表 document_type字段添加备注  comm
    02-10
  • MySQL与Oracle 差异比较之六触发器
    触发器编号类别ORACLEMYSQL注释1创建触发器语句不同create or replace trigger TG_ES_FAC_UNIT  before insert or update or delete on ES_FAC_UNIT  for each rowcreate trigger `hs_esbs`.`TG_INSERT_ES_FAC_UNIT` BEFORE INSERT on `hs_esbs`.`es_fac_u
    02-10
点击排行