【问题标题】:SQL subquery and Joins giving same or different result (oracle)SQL 子查询和连接给出相同或不同的结果(oracle)
【发布时间】:2014-07-01 19:42:07
【问题描述】:

由于 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)

【问题讨论】:

  • 他们看起来和我很像。我的建议是比较他们的执行计划。我希望它们是相似的,但谁知道呢。
  • 是的,它们非常相似……尤其是执行连接的顺序。但是第二个查询要快 20 倍...

标签: sql oracle optimization query-optimization


【解决方案1】:

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

没有where 子句,它们是不等价的。 t_link 中的重复项(相对于 join 键)将导致重复行。但是,您正在寻找没有匹配项,因此这不是问题。当不匹配时,两个版本应该是等价的。

【讨论】:

    【解决方案2】:

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

    查询 1 减 查询2

    如果显示任何结果,它们是不一样的。

    你必须把它们翻转过来才能尝试另一种方式......

    查询 2 减 查询1

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

    【讨论】:

    • 我用减号进行了测试,但我不想错过任何测试用例......我所有的减号测试都是空的,但是......也许一个案例不起作用......跨度>
    • 如果 T_LINK.ID1 和 T_LINK.ID2 是唯一的,那么您应该没有问题。如果您在 T_LINK 中有两条记录具有相同的 ID1 和 ID2,并且 IDL 在两者上都为空,则第一个查询将显示相同的 ID1 和 ID2 两次,因为不同的是在子查询中而不是在主查询中它在您的第二个查询中,因此您的第二个查询只会返回一条记录。
    • 是的,我的目标 T_LINK 在 ID1 和 ID2 上有一个唯一索引。
    【解决方案3】:

    这可能是不同的:查看执行计划中的这些行:

    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_LINKH1H2 连接起来,而不是一个临时表,并允许它利用在这些表上构建的索引,从而使您的速度提高20 倍。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-25
        • 1970-01-01
        • 2021-06-02
        • 1970-01-01
        • 1970-01-01
        • 2013-09-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多