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

# 类别 版本
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")

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

  1. CockroachDB学习笔记——[译]CockroachDB中的SQL:映射表中数据到键值存储

    CockroachDB学习笔记--[译]CockroachDB中的SQL:映射表中数据到键值存储 原文标题:SQL in CockroachDB: Mapping Table Data to Key- ...

  2. 2.oracle分页,找到员工表中薪水大于本部门平均薪水的员工

     ROWNUM的知识点 A ROWNUM依照oracle的默认机制生成. B rownum仅仅能使用<=  <号,不能使用>  >= rownum的实现机制 rownum表 ...

  3. oracle通过sql随机取表中的10条记录

    oracle通过sql随机取表中的10条记录: SELECT * FROM (SELECT * FROM T_USER ORDER BY DBMS_RANDOM.RANDOM()) WHERE Row ...

  4. Oracle 取两个表中数据的交集并集差异集合

    Oracle 取两个表中数据的交集 关键字: Oracle 取两个表中数据的交集 INTERSECT Oracle 作为一个大型的关系数据库,日常应用中往往需要提取两个表的交集数据 例如现有如下表,要 ...

  5. Oracle 11g对大表中添加DEFAULT值的NOT NULL字段速度有大幅度的提升

    在一张2000万的表上增加了一个字段并字段一个默认值,执行这条语句(alter table tablename add new_col default ‘col’)一个小时没有执行完,问我有没有其他解 ...

  6. **SQL某一表中重复某一字段重复记录查询与处理

    sql某一表中重复某一字段重复记录查询与处理   1.查询出重复记录  select 重复记录字段 form  数据表 group by houseno having count(重复记录字段)> ...

  7. SQL语句 在一个表中插入新字段

    SQL语句 在一个表中插入新字段: alter table 表名 add 字段名 字段类型 例: alter table OpenCourses add Audio varchar(50)alter ...

  8. EF Core中,通过实体类向SQL Server数据库表中插入数据后,实体对象是如何得到数据库表中的默认值的

    我们使用EF Core的实体类向SQL Server数据库表中插入数据后,如果数据库表中有自增列或默认值列,那么EF Core的实体对象也会返回插入到数据库表中的默认值. 下面我们通过例子来展示,EF ...

  9. 向SQL Server 现有表中添加新列并添加描述.

    注: sql server 2005 及以上支持. 版本估计是不支持(工作环境2005,2008). 工作需要, 需要向SQL Server 现有表中添加新列并添加描述. 从而有个如下存储过程. (先 ...

随机推荐

  1. klassVtable与klassItable

    klassVtable与klassItable类用来实现Java方法的多态,也可以叫动态绑定,是指在应用执行期间通过判断接受对象的实际类型,根据实际类型调用对应的方法.C++为了实现多态,在对象中嵌入 ...

  2. C#LeetCode刷题之#682-棒球比赛(Baseball Game)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4028 访问. 你现在是棒球比赛记录员. 给定一个字符串列表,每个 ...

  3. C#LeetCode刷题之#599-两个列表的最小索引总和​​​​​​​​​​​​​​(Minimum Index Sum of Two Lists)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3802 访问. 假设Andy和Doris想在晚餐时选择一家餐厅,并 ...

  4. ElasticSearch 7.8.1集群搭建

    通往集群的大门 集群由什么用? 高可用 高可用(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间.如果系统每运行100个时间 ...

  5. 阿里云日志服务SLS

    前言: 刚入职实习了几天,我发现我的任务就是学习阿里云日志服务这块业务内容,这个功能和mysql一样,但是速度和视觉却是甩mysql这类数据库几条街. 当得知公司没人会这项技术后(在这之前我也没听过, ...

  6. pyttsx3 的使用教程

    import pyttsx3 def use_pyttsx3(): # 创建对象 engine = pyttsx3.init() # 获取当前语音速率 rate = engine.getPropert ...

  7. 谈谈BUG严重级别(severity)管理

    在软件工程理论中,BUG严重级别(severity)是用于指示软件质量问题导致的负面影响的程度.但在大部分实际的软件开发组织中,对BUG严重级别(severity)的定义和使用常常充斥着大量的争议和分 ...

  8. 根据appid跳到App Store某个APP的详情页

    需求 本手机是否装了某个APP 示例百度appid 382201985  scheme BaiduSSO:// 1.是,直接打开百度APP 2.否,跳到App Store百度APP的详情页 NSStr ...

  9. Qt 实现 异形 窗体&按钮

    //关键部分代码如下//设置异形窗体 //setWindowOpacity(0.5);//设置窗体透明度 0完全透明,1完全不透明 this->setWindowFlag(Qt::Framele ...

  10. Spring Boot 如何解决项目启动时初始化资源

    在我们实际工作中,总会遇到这样需求,在项目启动的时候需要做一些初始化的操作,比如初始化线程池,提前加载好加密证书等.今天就给大家介绍一个 Spring Boot 神器,专门帮助大家解决项目启动初始化资 ...