zoukankan      html  css  js  c++  java
  • 半联结&反联结!

    半联结是在两个数据集(表)之间的联结,其中第一个数据集中的数据行在决定是否返回时会根据在另一个数据集中出现或不出现至少一个相匹配的数据行来确定。“不出先”匹配行——这是半联结的一种特殊形式,称为反联结。

    标准的内联结与半联结之间最主要的区别在于在半联结中,第1个数据集中的每一条记录至返回一次,而不管在第二个数据集中有几条匹配的数据。这个定义表明这个查询的实际处理过程可以通过在找到第1个匹配以后马上停止第二个查询来进行优化。

    从本质上来说,这就是半联结:可以通过在查询2执行完成之前停止处理该查询来进行优化。这种联结技术在oracle基于成本的优化器中查询中又包含在IN或EXISTS句中的子查询时是一种可选方案。

    1、半联结

    /*+ SEMIJOIN */  进行半联结(优化器选用使用哪种类型)。
    /*+ NO_SEMIJOIN */  显示的意味着不行进半联结。

    1. SQL> select * from emp order by job;  
    2.   
    3.      EMPNO ENAME      JOB              MGR HIREDATE              SAL       COMM     DEPTNO  
    4. ---------- ---------- --------- ---------- -------------- ---------- ---------- ----------  
    5.       7788 SCOTT      ANALYST         7566 19-4月 -87           3000                    20  
    6.       7902 FORD       ANALYST         7566 03-12月-81           3000                    20  
    7.       7934 MILLER     CLERK           7782 23-1月 -82           1300                    10  
    8.       7900 JAMES      CLERK           7698 03-12月-81            950                    30  
    9.       7369 SMITH      CLERK           7902 17-12月-80            800                    20  
    10.       7876 ADAMS      CLERK           7788 23-5月 -87           1100                    20  
    11.       7698 BLAKE      MANAGER         7839 01-5月 -81           2850                    30  
    12.       7566 JONES      MANAGER         7839 02-4月 -81           2975                    20  
    13.       7782 CLARK      MANAGER         7839 09-6月 -81           2450                    10  
    14.       7839 KING       PRESIDENT            17-11月-81           5000                    10  
    15.       7844 TURNER     SALESMAN        7698 08-9月 -81           1500          0         30  
    16.   
    17.      EMPNO ENAME      JOB              MGR HIREDATE              SAL       COMM     DEPTNO  
    18. ---------- ---------- --------- ---------- -------------- ---------- ---------- ----------  
    19.       7654 MARTIN     SALESMAN        7698 28-9月 -81           1250       1400         30  
    20.       7521 WARD       SALESMAN        7698 22-2月 -81           1250        500         30  
    21.       7499 ALLEN      SALESMAN        7698 20-2月 -81           1600        300         30  
    22.   
    23. 已选择14行。  

    分析上面的数据可以看出JOB='SALESMAN'的DEPTNO有4条重复的记录,值都是30。那么如下的子查询返回的记录就有重复的记录!

    1. select e.ename, e.job, e.sal  
    2.   from emp e  
    3.  where e.deptno in (select d.deptno from emp d where d.job = 'SALESMAN');  
    4.   
    5. select e.ename, e.job, e.sal  
    6.   from emp e  
    7.  where exists (select null  
    8.           from emp d  
    9.          where e.deptno = d.deptno  
    10.            and d.job = 'SALESMAN');  

    看执行计划:

    1. SQL> select e.ename, e.job, e.sal  
    2.   2    from emp e  
    3.   3   where e.deptno in (select d.deptno from emp d where d.job = 'SALESMAN');  
    4.   
    5. ENAME      JOB              SAL  
    6. ---------- --------- ----------  
    7. JAMES      CLERK            950  
    8. TURNER     SALESMAN        1500  
    9. BLAKE      MANAGER         2850  
    10. MARTIN     SALESMAN        1250  
    11. WARD       SALESMAN        1250  
    12. ALLEN      SALESMAN        1600  
    13.   
    14. 已选择6行。  
    15.   
    16.   
    17. 执行计划  
    18. ----------------------------------------------------------  
    19. Plan hash value: 977554918  
    20.   
    21. ---------------------------------------------------------------------------  
    22. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
    23. ---------------------------------------------------------------------------  
    24. |   0 | SELECT STATEMENT   |      |    14 |   448 |     7  (15)| 00:00:01 |  
    25. |*  1 |  HASH JOIN SEMI    |      |    14 |   448 |     7  (15)| 00:00:01 |  
    26. |   2 |   TABLE ACCESS FULL| EMP  |    14 |   294 |     3   (0)| 00:00:01 |  
    27. |*  3 |   TABLE ACCESS FULL| EMP  |     3 |    33 |     3   (0)| 00:00:01 |  
    28. ---------------------------------------------------------------------------  
    29.   
    30. Predicate Information (identified by operation id):  
    31. ---------------------------------------------------  
    32.   
    33.    1 - access("E"."DEPTNO"="D"."DEPTNO")  
    34.    3 - filter("D"."JOB"='SALESMAN')  
    35.   
    36. SQL>   
    37. SQL>   
    38. SQL> select e.ename, e.job, e.sal  
    39.   2    from emp e  
    40.   3   where exists (select null  
    41.   4            from emp d  
    42.   5           where e.deptno = d.deptno  
    43.   6             and d.job = 'SALESMAN');  
    44.   
    45. ENAME      JOB              SAL  
    46. ---------- --------- ----------  
    47. JAMES      CLERK            950  
    48. TURNER     SALESMAN        1500  
    49. BLAKE      MANAGER         2850  
    50. MARTIN     SALESMAN        1250  
    51. WARD       SALESMAN        1250  
    52. ALLEN      SALESMAN        1600  
    53.   
    54. 已选择6行。  
    55.   
    56.   
    57. 执行计划  
    58. ----------------------------------------------------------  
    59. Plan hash value: 977554918  
    60.   
    61. ---------------------------------------------------------------------------  
    62. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
    63. ---------------------------------------------------------------------------  
    64. |   0 | SELECT STATEMENT   |      |    14 |   448 |     7  (15)| 00:00:01 |  
    65. |*  1 |  HASH JOIN SEMI    |      |    14 |   448 |     7  (15)| 00:00:01 |  
    66. |   2 |   TABLE ACCESS FULL| EMP  |    14 |   294 |     3   (0)| 00:00:01 |  
    67. |*  3 |   TABLE ACCESS FULL| EMP  |     3 |    33 |     3   (0)| 00:00:01 |  
    68. ---------------------------------------------------------------------------  
    69.   
    70. Predicate Information (identified by operation id):  
    71. ---------------------------------------------------  
    72.   
    73.    1 - access("E"."DEPTNO"="D"."DEPTNO")  
    74.    3 - filter("D"."JOB"='SALESMAN')  

    使用IN和EXISTS的执行计划是一致的,这一点就为了消除长期以来人们认为的使用EXISTS查询与使用IN查询的处理方法很不相同这种观点。注意执行计划中的“SEMI”就代表使用了半联结!

    1. SQL> select e.ename, e.job, e.sal  
    2.   2    from emp e  
    3.   3   where e.deptno in (select /*+ no_semijoin */  
    4.   4                       d.deptno  
    5.   5                        from emp d  
    6.   6                       where d.job = 'SALESMAN');  
    7.   
    8. ENAME      JOB              SAL  
    9. ---------- --------- ----------  
    10. ALLEN      SALESMAN        1600  
    11. WARD       SALESMAN        1250  
    12. MARTIN     SALESMAN        1250  
    13. BLAKE      MANAGER         2850  
    14. TURNER     SALESMAN        1500  
    15. JAMES      CLERK            950  
    16.   
    17. 已选择6行。  
    18.   
    19.   
    20. 执行计划  
    21. ----------------------------------------------------------  
    22. Plan hash value: 2389097100  
    23.   
    24. ---------------------------------------------------------------------------------  
    25. | Id  | Operation            | Name     | Rows  | Bytes | Cost (%CPU)| Time     |  
    26. ---------------------------------------------------------------------------------  
    27. |   0 | SELECT STATEMENT     |          |     9 |   306 |     8  (25)| 00:00:01 |  
    28. |*  1 |  HASH JOIN           |          |     9 |   306 |     8  (25)| 00:00:01 |  
    29. |   2 |   VIEW               | VW_NSO_1 |     2 |    26 |     4  (25)| 00:00:01 |  
    30. |   3 |    HASH UNIQUE       |          |     2 |    22 |     4  (25)| 00:00:01 |  
    31. |*  4 |     TABLE ACCESS FULL| EMP      |     3 |    33 |     3   (0)| 00:00:01 |  
    32. |   5 |   TABLE ACCESS FULL  | EMP      |    14 |   294 |     3   (0)| 00:00:01 |  
    33. ---------------------------------------------------------------------------------  
    34.   
    35. Predicate Information (identified by operation id):  
    36. ---------------------------------------------------  
    37.   
    38.    1 - access("E"."DEPTNO"="DEPTNO")  
    39.    4 - filter("D"."JOB"='SALESMAN')  
    40.   
    41. SQL>   
    42. SQL>   
    43. SQL> select e.ename, e.job, e.sal  
    44.   2    from emp e  
    45.   3   where exists (select /*+ no_semijoin */  
    46.   4           null  
    47.   5            from emp d  
    48.   6           where e.deptno = d.deptno  
    49.   7             and d.job = 'SALESMAN');  
    50.   
    51. ENAME      JOB              SAL  
    52. ---------- --------- ----------  
    53. ALLEN      SALESMAN        1600  
    54. WARD       SALESMAN        1250  
    55. MARTIN     SALESMAN        1250  
    56. BLAKE      MANAGER         2850  
    57. TURNER     SALESMAN        1500  
    58. JAMES      CLERK            950  
    59.   
    60. 已选择6行。  
    61.   
    62.   
    63. 执行计划  
    64. ----------------------------------------------------------  
    65. Plan hash value: 2561671593  
    66.   
    67. ---------------------------------------------------------------------------  
    68. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
    69. ---------------------------------------------------------------------------  
    70. |   0 | SELECT STATEMENT   |      |     5 |   105 |    12   (0)| 00:00:01 |  
    71. |*  1 |  FILTER            |      |       |       |            |          |  
    72. |   2 |   TABLE ACCESS FULL| EMP  |    14 |   294 |     3   (0)| 00:00:01 |  
    73. |*  3 |   TABLE ACCESS FULL| EMP  |     1 |    11 |     3   (0)| 00:00:01 |  
    74. ---------------------------------------------------------------------------  
    75.   
    76. Predicate Information (identified by operation id):  
    77. ---------------------------------------------------  
    78.   
    79.    1 - filter( EXISTS (SELECT 0 FROM "EMP" "D" WHERE  
    80.               "D"."JOB"='SALESMAN' AND "D"."DEPTNO"=:B1))  
    81.    3 - filter("D"."JOB"='SALESMAN' AND "D"."DEPTNO"=:B1)  

    使用NO_SEMIJOIN提示关闭了优化器使用半联结的能力。可以看见使用使用IN和EXISTS的执行计划还不一样了。

    2、反联结

    /*+ ANTIJOIN */  进行反联接(优化器决定具体类型)
    /*+ USE_ANTI */  ANTIJOIN提示的旧版本

    1. SQL> select e.ename, e.job, e.sal  
    2.   2    from emp e  
    3.   3   where e.deptno not in  
    4.   4         (select d.deptno from emp d where d.job = 'PRESIDENT');  
    5.   
    6. ENAME      JOB              SAL  
    7. ---------- --------- ----------  
    8. JAMES      CLERK            950  
    9. TURNER     SALESMAN        1500  
    10. BLAKE      MANAGER         2850  
    11. MARTIN     SALESMAN        1250  
    12. WARD       SALESMAN        1250  
    13. ALLEN      SALESMAN        1600  
    14. FORD       ANALYST         3000  
    15. ADAMS      CLERK           1100  
    16. SCOTT      ANALYST         3000  
    17. JONES      MANAGER         2975  
    18. SMITH      CLERK            800  
    19.   
    20. 已选择11行。  
    21.   
    22.   
    23. 执行计划  
    24. ----------------------------------------------------------  
    25. Plan hash value: 4002838083  
    26.   
    27. ---------------------------------------------------------------------------  
    28. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
    29. ---------------------------------------------------------------------------  
    30. |   0 | SELECT STATEMENT   |      |     5 |   160 |     7  (15)| 00:00:01 |  
    31. |*  1 |  HASH JOIN ANTI NA |      |     5 |   160 |     7  (15)| 00:00:01 |  
    32. |   2 |   TABLE ACCESS FULL| EMP  |    14 |   294 |     3   (0)| 00:00:01 |  
    33. |*  3 |   TABLE ACCESS FULL| EMP  |     3 |    33 |     3   (0)| 00:00:01 |  
    34. ---------------------------------------------------------------------------  
    35.   
    36. Predicate Information (identified by operation id):  
    37. ---------------------------------------------------  
    38.   
    39.    1 - access("E"."DEPTNO"="D"."DEPTNO")  
    40.    3 - filter("D"."JOB"='PRESIDENT')  
    41.   
    42. SQL>   
    43. SQL>   
    44. SQL> select e.ename, e.job, e.sal  
    45.   2    from emp e  
    46.   3   where not exists (select null  
    47.   4            from emp d  
    48.   5           where e.deptno = d.deptno  
    49.   6             and d.job = 'PRESIDENT');  
    50.   
    51. ENAME      JOB              SAL  
    52. ---------- --------- ----------  
    53. JAMES      CLERK            950  
    54. TURNER     SALESMAN        1500  
    55. BLAKE      MANAGER         2850  
    56. MARTIN     SALESMAN        1250  
    57. WARD       SALESMAN        1250  
    58. ALLEN      SALESMAN        1600  
    59. FORD       ANALYST         3000  
    60. ADAMS      CLERK           1100  
    61. SCOTT      ANALYST         3000  
    62. JONES      MANAGER         2975  
    63. SMITH      CLERK            800  
    64.   
    65. 已选择11行。  
    66.   
    67.   
    68. 执行计划  
    69. ----------------------------------------------------------  
    70. Plan hash value: 3353202012  
    71.   
    72. ---------------------------------------------------------------------------  
    73. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
    74. ---------------------------------------------------------------------------  
    75. |   0 | SELECT STATEMENT   |      |     5 |   160 |     7  (15)| 00:00:01 |  
    76. |*  1 |  HASH JOIN ANTI    |      |     5 |   160 |     7  (15)| 00:00:01 |  
    77. |   2 |   TABLE ACCESS FULL| EMP  |    14 |   294 |     3   (0)| 00:00:01 |  
    78. |*  3 |   TABLE ACCESS FULL| EMP  |     3 |    33 |     3   (0)| 00:00:01 |  
    79. ---------------------------------------------------------------------------  
    80.   
    81. Predicate Information (identified by operation id):  
    82. ---------------------------------------------------  
    83.   
    84.    1 - access("E"."DEPTNO"="D"."DEPTNO")  
    85.    3 - filter("D"."JOB"='PRESIDENT')  

    执行计划中的“ANTI” 就是反联结的意思,而在NOT IN的执行计划中还有“NA” 表示考虑NULL值的意思。

    转载:http://blog.csdn.net/zq9017197/article/details/8439353

  • 相关阅读:
    【leetcode】1365. How Many Numbers Are Smaller Than the Current Number
    【leetcode】1363. Largest Multiple of Three
    【leetcode】1362. Closest Divisors
    【leetcode】1361. Validate Binary Tree Nodes
    【leetcode】1360. Number of Days Between Two Dates
    【leetcode】1359. Count All Valid Pickup and Delivery Options
    【leetcode】1357. Apply Discount Every n Orders
    【leetcode】1356. Sort Integers by The Number of 1 Bits
    ISE应用入门的一些问题
    DDR的型号问题
  • 原文地址:https://www.cnblogs.com/future2012lg/p/4095468.html
Copyright © 2011-2022 走看看