SQL子查询和联接给出相同或不同的结果(oracle)

时间:2014-06-30 11:35:32

标签: sql oracle optimization query-optimization

由于Oracle上有大量数据,我正在努力优化查询。

有一个这样的查询。

使用子查询:

SELECT
  STG.ID1,
  STG.ID2
FROM (SELECT 
        DISTINCT
        H1.ID1,
        H2.ID2
      FROM T_STGDV STG
      INNER JOIN T_HUB1 H1 ON STG.BK1 = H1.BK1
      INNER JOIN T_HUB2 H2 ON STG.BK2 = H2.BK2 ) STG
LEFT OUTER JOIN T_LINK L ON  L.ID1 = STG.ID1 AND L.ID2 = STG.ID2
WHERE L.IDL IS NULL;

我正在进行此优化:

SELECT 
  DISTINCT
  H1.ID1,
  H2.ID2
FROM T_STGDV STG
INNER JOIN T_HUB1 H1 ON STG.BK1 = H1.BK1
INNER JOIN T_HUB2 H2 ON STG.BK2 = H2.BK2 
LEFT OUTER JOIN T_LINK L ON L.ID1 = H1.ID1 AND L.ID2 = H2.ID2
WHERE L.IDL IS NULL;

我想知道结果是否相同,行为是一样的。

我做了一些测试,我没有找到差异,但也许我错过了一些测试用例?

知道这些查询之间有什么区别吗?

感谢。

一些细节,这些测试表的解释计划(成本不代表实际表格)

第一个查询:

Plan hash value: 2680307749

-----------------------------------------------------------------------------------
| Id  | Operation               | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |         |     1 |    65 |    11  (28)| 00:00:01 |
|*  1 |  FILTER                 |         |       |       |            |          |
|*  2 |   HASH JOIN OUTER       |         |     1 |    65 |    11  (28)| 00:00:01 |
|   3 |    VIEW                 |         |     1 |    26 |     8  (25)| 00:00:01 |
|   4 |     HASH UNIQUE         |         |     1 |   134 |     8  (25)| 00:00:01 |
|*  5 |      HASH JOIN          |         |     1 |   134 |     7  (15)| 00:00:01 |
|*  6 |       HASH JOIN         |         |     1 |    94 |     5  (20)| 00:00:01 |
|   7 |        TABLE ACCESS FULL| T_STGDV |     1 |    54 |     2   (0)| 00:00:01 |
|   8 |        TABLE ACCESS FULL| T_HUB1  |     2 |    80 |     2   (0)| 00:00:01 |
|   9 |       TABLE ACCESS FULL | T_HUB2  |     2 |    80 |     2   (0)| 00:00:01 |
|  10 |    TABLE ACCESS FULL    | T_LINK  |     3 |   117 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

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

   1 - filter("L"."IDL" IS NULL)
   2 - access("L"."ID2"(+)="STG"."ID2" AND "L"."ID1"(+)="STG"."ID1")
   5 - access("STG"."BK2"="H2"."BK2")
   6 - access("STG"."BK1"="H1"."BK1")

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

第二个查询

Plan hash value: 2149614538

-----------------------------------------------------------------------------------
| Id  | Operation               | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |         |     1 |    65 |    11  (28)| 00:00:01 |
|   1 |  HASH UNIQUE            |         |     1 |    65 |    11  (28)| 00:00:01 |
|*  2 |   FILTER                |         |       |       |            |          |
|*  3 |    HASH JOIN OUTER      |         |     1 |    65 |    10  (20)| 00:00:01 |
|   4 |     VIEW                |         |     1 |    26 |     7  (15)| 00:00:01 |
|*  5 |      HASH JOIN          |         |     1 |   134 |     7  (15)| 00:00:01 |
|*  6 |       HASH JOIN         |         |     1 |    94 |     5  (20)| 00:00:01 |
|   7 |        TABLE ACCESS FULL| T_STGDV |     1 |    54 |     2   (0)| 00:00:01 |
|   8 |        TABLE ACCESS FULL| T_HUB1  |     2 |    80 |     2   (0)| 00:00:01 |
|   9 |       TABLE ACCESS FULL | T_HUB2  |     2 |    80 |     2   (0)| 00:00:01 |
|  10 |     TABLE ACCESS FULL   | T_LINK  |     3 |   117 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

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

   2 - filter("L"."IDL" IS NULL)
   3 - access("L"."ID2"(+)="H2"."ID2" AND "L"."ID1"(+)="H1"."ID1")
   5 - access("STG"."BK2"="H2"."BK2")
   6 - access("STG"."BK1"="H1"."BK1")

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

4 个答案:

答案 0 :(得分:0)

由于where子句,查询看起来与我相同。

如果没有where条款,它们就不相同了。 t_link中的重复项(相对于join键)将导致重复的行。但是,您正在寻找没有匹配项,所以这不是问题。如果没有匹配,则两个版本应该是等效的。

答案 1 :(得分:0)

如果您想使用当前数据集测试它们,可以使用减号。

查询1 减去 查询2

如果显示任何结果,则它们不相同。

你必须翻转它们以尝试另一种方式......

查询2 减去 查询1

如果两个测试都没有返回任何记录,则查询对您当前的数据集具有相同的效果。

答案 2 :(得分:0)

这可能是不同的:在执行计划中查看以下几行:

2 - access("L"."ID2"(+)="STG"."ID2" AND "L"."ID1"(+)="STG"."ID1")

3 - access("L"."ID2"(+)="H2"."ID2" AND "L"."ID1"(+)="H1"."ID1")

STG是Oracle在查询期间创建的临时表(T_STGDV别名与子查询别名之间的模糊不清是重写查询的理由)。而这个临时表当然没有索引。在您进行重构之后,Oracle优化器开始使用T_LINKH1加入H2而不是临时表,并允许它使用在这些表上构建的索引,从而使您的速度提高20倍

答案 3 :(得分:0)

经过测试,结果相同。第二个更有效率。