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

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

下面进入正题

有个员工表emp如下:

  1. CREATE TABLE emp
  2. (
  3. id NUMBER not null primary key,
  4. name NVARCHAR2(60) not null,
  5. salary NUMBER(6,0) NOT NULL,
  6. deptid NUMBER(2,0) not null
  7. )

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

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

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

  1. SQL> select max(salary),deptid from emp
  2. 2 group by deptid
  3. 3 order by deptid;
  4.  
  5. MAX(SALARY) DEPTID
  6. ----------- ----------
  7. 49944 0
  8. 49991 1
  9. 49988 2
  10. 49993 3
  11. 49927 4
  12. 49988 5
  13. 49924 6
  14. 49923 7
  15. 49848 8
  16. 49934 9
  17. 49894 10
  18.  
  19. 已选择11行。
  20.  
  21. 已用时间: 00: 00: 00.01

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

  1. 1.
  2. select a.id,a.name,a.salary,a.deptid from emp a
  3. where salary=(select max(salary) from emp b where a.deptid=b.deptid)
  4. order by a.id
  5.  
  6. 2.
  7. select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp
  8. group by deptid
  9. ) e2
  10. where e1.deptid=e2.deptid and e1.salary=e2.max_sal
  11. order by e1.id
  12.  
  13. 3.
  14. select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e)
  15. where salary=max_sal
  16. order by id

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

# sql Time elapsed Cost
1
  1. 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.03 41
2
  1. 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: 07.92 641
3
  1. 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.01 471

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

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

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

附:耗时比较:

  1. SQL> select a.id,a.name,a.salary,a.deptid from emp a
  2. 2 where salary=(select max(salary) from emp b where a.deptid=b.deptid)
  3. 3 order by a.id;
  4.  
  5. ID NAME
  6. SALARY DEPTID
  7. ---------- ------------------------------------------------------------------------------------------------------------------------ ---------- ----------
  8. 1073 UGJURPQV
  9. 49993 3
  10. 1356 UPHXQELWTDBLFYRBSHSF
  11. 49991 1
  12. 2946 SGSJBCABNNQXGORWPO
  13. 49924 6
  14. 3111 PQMATSYLQNZR
  15. 49848 8
  16. 3516 CBXGAVDIHITQ
  17. 49944 0
  18. 6218 LPZAQPOKQSJNAMNTOT
  19. 49923 7
  20. 7874 LBQPRRDVXUQS
  21. 49988 5
  22. 9032 OPVFSDKNZ
  23. 49988 2
  24. 9329 XRNKOKCCUORV
  25. 49934 9
  26. 9437 WQDWBTNEKJJYFL
  27. 49894 10
  28. 9979 YLXJXJPRKKBXAQIE
  29. 49927 4
  30.  
  31. 已选择11行。
  32.  
  33. 已用时间: 00: 00: 00.03
  34.  
  35. SQL> select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp
  36. 2 group by deptid
  37. 3 ) e2
  38. 4 where e1.deptid=e2.deptid and e1.salary=e2.max_sal
  39. 5 order by e1.id;
  40.  
  41. ID NAME
  42. SALARY DEPTID
  43. ---------- ------------------------------------------------------------------------------------------------------------------------ ---------- ----------
  44. 1073 UGJURPQV
  45. 49993 3
  46. 1356 UPHXQELWTDBLFYRBSHSF
  47. 49991 1
  48. 2946 SGSJBCABNNQXGORWPO
  49. 49924 6
  50. 3111 PQMATSYLQNZR
  51. 49848 8
  52. 3516 CBXGAVDIHITQ
  53. 49944 0
  54. 6218 LPZAQPOKQSJNAMNTOT
  55. 49923 7
  56. 7874 LBQPRRDVXUQS
  57. 49988 5
  58. 9032 OPVFSDKNZ
  59. 49988 2
  60. 9329 XRNKOKCCUORV
  61. 49934 9
  62. 9437 WQDWBTNEKJJYFL
  63. 49894 10
  64. 9979 YLXJXJPRKKBXAQIE
  65. 49927 4
  66.  
  67. 已选择11行。
  68.  
  69. 已用时间: 00: 00: 07.92
  70.  
  71. SQL> select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e)
  72. 2 where salary=max_sal
  73. 3 order by id;
  74.  
  75. ID NAME
  76. SALARY DEPTID
  77. ---------- ------------------------------------------------------------------------------------------------------------------------ ---------- ----------
  78. 1073 UGJURPQV
  79. 49993 3
  80. 1356 UPHXQELWTDBLFYRBSHSF
  81. 49991 1
  82. 2946 SGSJBCABNNQXGORWPO
  83. 49924 6
  84. 3111 PQMATSYLQNZR
  85. 49848 8
  86. 3516 CBXGAVDIHITQ
  87. 49944 0
  88. 6218 LPZAQPOKQSJNAMNTOT
  89. 49923 7
  90. 7874 LBQPRRDVXUQS
  91. 49988 5
  92. 9032 OPVFSDKNZ
  93. 49988 2
  94. 9329 XRNKOKCCUORV
  95. 49934 9
  96. 9437 WQDWBTNEKJJYFL
  97. 49894 10
  98. 9979 YLXJXJPRKKBXAQIE
  99. 49927 4
  100.  
  101. 已选择11行。
  102.  
  103. 已用时间: 00: 00: 00.01

执行计划比较:

  1. SQL> select a.id,a.name,a.salary,a.deptid from emp a
  2. 2 where salary=(select max(salary) from emp b where a.deptid=b.deptid)
  3. 3 order by a.id;
  4. 已用时间: 00: 00: 00.00
  5.  
  6. 执行计划
  7. ----------------------------------------------------------
  8. Plan hash value: 1231226589
  9.  
  10. ---------------------------------------------------------------------------------
  11. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
  12. ---------------------------------------------------------------------------------
  13. | 0 | SELECT STATEMENT | | 1 | 127 | 41 (8)| 00:00:01 |
  14. | 1 | SORT ORDER BY | | 1 | 127 | 41 (8)| 00:00:01 |
  15. |* 2 | HASH JOIN | | 1 | 127 | 40 (5)| 00:00:01 |
  16. | 3 | VIEW | VW_SQ_1 | 9121 | 231K| 21 (10)| 00:00:01 |
  17. | 4 | HASH GROUP BY | | 9121 | 231K| 21 (10)| 00:00:01 |
  18. | 5 | TABLE ACCESS FULL| EMP | 9121 | 231K| 19 (0)| 00:00:01 |
  19. | 6 | TABLE ACCESS FULL | EMP | 9121 | 899K| 19 (0)| 00:00:01 |
  20. ---------------------------------------------------------------------------------
  21.  
  22. Predicate Information (identified by operation id):
  23. ---------------------------------------------------
  24.  
  25. 2 - access("SALARY"="MAX(SALARY)" AND "A"."DEPTID"="ITEM_1")
  26.  
  27. Note
  28. -----
  29. - dynamic sampling used for this statement (level=2)
  30.  
  31. SQL> select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp
  32. 2 group by deptid
  33. 3 ) e2
  34. 4 where e1.deptid=e2.deptid and e1.salary=e2.max_sal
  35. 5 order by e1.id;
  36. 已用时间: 00: 00: 00.00
  37.  
  38. 执行计划
  39. ----------------------------------------------------------
  40. Plan hash value: 962461943
  41.  
  42. -----------------------------------------------------------------------------
  43. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
  44. -----------------------------------------------------------------------------
  45. | 0 | SELECT STATEMENT | | 7562K| 1002M| 641 (95)| 00:00:08 |
  46. |* 1 | FILTER | | | | | |
  47. | 2 | SORT GROUP BY | | 7562K| 1002M| 641 (95)| 00:00:08 |
  48. |* 3 | HASH JOIN | | 7562K| 1002M| 92 (59)| 00:00:02 |
  49. | 4 | TABLE ACCESS FULL| EMP | 9121 | 231K| 19 (0)| 00:00:01 |
  50. | 5 | TABLE ACCESS FULL| EMP | 9121 | 1006K| 19 (0)| 00:00:01 |
  51. -----------------------------------------------------------------------------
  52.  
  53. Predicate Information (identified by operation id):
  54. ---------------------------------------------------
  55.  
  56. 1 - filter("E1"."SALARY"=MAX("SALARY"))
  57. 3 - access("E1"."DEPTID"="DEPTID")
  58.  
  59. Note
  60. -----
  61. - dynamic sampling used for this statement (level=2)
  62.  
  63. SQL> select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e)
  64. 2 where salary=max_sal
  65. 3 order by id;
  66. 已用时间: 00: 00: 00.00
  67.  
  68. 执行计划
  69. ----------------------------------------------------------
  70. Plan hash value: 3418936035
  71.  
  72. -------------------------------------------------------------------------------------
  73. | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
  74. -------------------------------------------------------------------------------------
  75. | 0 | SELECT STATEMENT | | 9121 | 1015K| | 471 (1)| 00:00:06 |
  76. | 1 | SORT ORDER BY | | 9121 | 1015K| 1168K| 471 (1)| 00:00:06 |
  77. |* 2 | VIEW | | 9121 | 1015K| | 234 (1)| 00:00:03 |
  78. | 3 | WINDOW SORT | | 9121 | 899K| 1056K| 234 (1)| 00:00:03 |
  79. | 4 | TABLE ACCESS FULL| EMP | 9121 | 899K| | 19 (0)| 00:00:01 |
  80. -------------------------------------------------------------------------------------
  81.  
  82. Predicate Information (identified by operation id):
  83. ---------------------------------------------------
  84.  
  85. 2 - filter("SALARY"="MAX_SAL")
  86.  
  87. Note
  88. -----
  89. - dynamic sampling used for this statement (level=2)

2020年1月19日

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

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

  1. Oracle版本:
    Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
  2. PL/SQL Release 12.2.0.1.0 - Production
  3. "CORE 12.2.0.1.0 Production"
  4. TNS for Linux: Version 12.2.0.1.0 - Production
  5. NLSRTL Version 12.2.0.1.0 - Production
  6.  
  7. #1
  8. EXPLAIN PLAN FOR
  9. select a.id,a.name,a.salary,a.deptid from emp a
  10. where salary=(select max(salary) from emp b where a.deptid=b.deptid)
  11. order by a.id
  12.  
  13. Plan hash value: 1231226589
  14.  
  15. ---------------------------------------------------------------------------------
  16. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
  17. ---------------------------------------------------------------------------------
  18. | 0 | SELECT STATEMENT | | 11 | 605 | 40 (5)| 00:00:01 |
  19. | 1 | SORT ORDER BY | | 11 | 605 | 40 (5)| 00:00:01 |
  20. |* 2 | HASH JOIN | | 11 | 605 | 39 (3)| 00:00:01 |
  21. | 3 | VIEW | VW_SQ_1 | 11 | 176 | 20 (5)| 00:00:01 |
  22. | 4 | HASH GROUP BY | | 11 | 88 | 20 (5)| 00:00:01 |
  23. | 5 | TABLE ACCESS FULL| EMP | 10000 | 80000 | 19 (0)| 00:00:01 |
  24. | 6 | TABLE ACCESS FULL | EMP | 10000 | 380K| 19 (0)| 00:00:01 |
  25. ---------------------------------------------------------------------------------
  26.  
  27. Predicate Information (identified by operation id):
  28. ---------------------------------------------------
  29.  
  30. 2 - access("SALARY"="MAX(SALARY)" AND "A"."DEPTID"="ITEM_1")
  31.  
  32. #2
  33. select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp
  34. group by deptid
  35. ) e2
  36. where e1.deptid=e2.deptid and e1.salary=e2.max_sal
  37. order by e1.id
  38.  
  39. Plan hash value: 2003893481
  40.  
  41. ------------------------------------------------------------------------------
  42. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
  43. ------------------------------------------------------------------------------
  44. | 0 | SELECT STATEMENT | | 11 | 605 | 40 (5)| 00:00:01 |
  45. | 1 | SORT ORDER BY | | 11 | 605 | 40 (5)| 00:00:01 |
  46. |* 2 | HASH JOIN | | 11 | 605 | 39 (3)| 00:00:01 |
  47. | 3 | VIEW | | 11 | 176 | 20 (5)| 00:00:01 |
  48. | 4 | HASH GROUP BY | | 11 | 88 | 20 (5)| 00:00:01 |
  49. | 5 | TABLE ACCESS FULL| EMP | 10000 | 80000 | 19 (0)| 00:00:01 |
  50. | 6 | TABLE ACCESS FULL | EMP | 10000 | 380K| 19 (0)| 00:00:01 |
  51. ------------------------------------------------------------------------------
  52.  
  53. Predicate Information (identified by operation id):
  54. ---------------------------------------------------
  55.  
  56. 2 - access("E1"."DEPTID"="E2"."DEPTID" AND
  57. "E1"."SALARY"="E2"."MAX_SAL")
  58.  
  59. #3
  60. select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e)
  61. where salary=max_sal
  62. order by id
  63.  
  64. Plan hash value: 3418936035
  65.  
  66. -------------------------------------------------------------------------------------
  67. | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
  68. -------------------------------------------------------------------------------------
  69. | 0 | SELECT STATEMENT | | 10000 | 1035K| | 365 (1)| 00:00:01 |
  70. | 1 | SORT ORDER BY | | 10000 | 1035K| 1192K| 365 (1)| 00:00:01 |
  71. |* 2 | VIEW | | 10000 | 1035K| | 121 (1)| 00:00:01 |
  72. | 3 | WINDOW SORT | | 10000 | 380K| 520K| 121 (1)| 00:00:01 |
  73. | 4 | TABLE ACCESS FULL| EMP | 10000 | 380K| | 19 (0)| 00:00:01 |
  74. -------------------------------------------------------------------------------------
  75.  
  76. Predicate Information (identified by operation id):
  77. ---------------------------------------------------
  78.  
  79. 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. C#LeetCode刷题之#155-最小栈(Min Stack)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4020 访问. 设计一个支持 push,pop,top 操作,并能 ...

  2. C#设计模式之0-简单工厂模式

    简单工厂模式(Simple Factory Pattern) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/387 访问 ...

  3. C#LeetCode刷题之#811-子域名访问计数​​​​​​​(Subdomain Visit Count)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3814 访问. 一个网站域名,如"discuss.lee ...

  4. Hyperledger Fabric介绍

    转载地址 https://blog.csdn.net/xiaonu123/article/details/81006936 简介 Hyperledger介绍 超级账本(Hyperledger)项目是首 ...

  5. 338. Counting Bits题目详解

    题目详情 Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate ...

  6. Istio Routing 实践掌握virtualservice/gateway/destinationrule/AB版本发布/金丝雀发布

    原文 在学习像 Istio 这样的新技术时,看一下示例应用程序总是一个好主意. Istio repo 有一些示例应用程序,但它们似乎有各种不足. 文档中的 BookInfo 是一个很好的示例. 但是, ...

  7. 关于Differentiated Services Field (DS Field)的诸多疑问

    Differentiated Services Field (DS Field) 先上疑问截图: 这是用wireshark抓包时协议树的某一项的展开结果:IPV4 header.其中有一项如下: 大家 ...

  8. 用C++基础语句写一个五子棋游戏

    (这是一个颜色会变化的呦) #include <iostream> using namespace std; int b[][]; int n; int m; void qipan() { ...

  9. C++生成元

    生成元对于正整数N,N的数字总和定义为N本身及其数字的总和.当M 是N的数字总和,我们称N为M的生成元. 例如,245的数字总和为256(= 245 + 2 + 4 + 5).因此,245是 256. ...

  10. java文件的写入和读取(按行)

    https://blog.csdn.net/Alexwym/article/details/81078417 https://blog.csdn.net/nickwong_/article/detai ...