2014-06-30 125 views
0

由于Oracle上的大量数据,我正在努力优化查询。SQL子查询和联接给出相同或不同的结果(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) 
+0

他们长得很像我。我的建议是比较他们的执行计划。我希望他们是相似的,但谁知道。 – AndreySarafanov

+0

是的,有非常相似的...尤其是执行连接的顺序。但第二个查询速度快20倍... – MisterT

回答

0

查询看起来与我相当,因为where条款。

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

0

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

查询1个 MINUS 查询2

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

你要翻转他们周围尝试过其他方式...

查询2 减号 查询1

如果两个测试返回任何记录,查询对你目前的效果相同数据集。

+0

我用减号做了测试,但我不想错过任何测试用例......我所有的减号测试都是空的,但是......可能有一种情况不适用。 。 – MisterT

+0

如果T_LINK.ID1和T_LINK.ID2是唯一的,则不应该有问题。如果在T_LINK中有两个记录具有相同的ID1和ID2,并且IDL在两者上均为空,则第一个查询将显示两次相同的ID1和ID2,因为distinct是在子查询中,而不是在主要select中作为它在你的第二个查询中,所以你的第二个查询只会返回一个记录。 – Bob

+0

是的,我的目标T_LINK在ID1和ID2上有唯一索引。 – MisterT

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

0

经过测试,结果一致。第二个更有效率。

相关问题