2

我有两个查询,我想了解哪个在性能和内存方面更好。我也欢迎这两个的其他选择。

查询一:

SELECT DISTINCT a.no,
   a.id1            ,
   a.id2
   FROM  tbl_b b         ,
         tbl_a a ,
         tbl_c c    ,
         tbl_d d
   WHERE (
          b.id1              = a.id1
      AND a.id1              = c.id1
      AND upper(c.flag)      = 'Y'
      AND c.id1              = d.id1
   )
   OR (
          b.id2              = a.id2
      AND a.id2              = c.id2
      AND upper(c.flag)      = 'Y'
      AND c.id2              = d.id2
)
AND d.id3 = 10

这里表 b 和 d 是运行超过 500,000 到数百万行的非常大的表,而表 a 相对较小。

我的要求是只从表 a 中提取那些 id(id1 或 id2)在 b、c、d 表中可用的记录,同时满足某些其他条件。

我手头的备用查询是

查询 2:

SELECT DISTINCT a.no,
   a.id1             ,
   a.id2
   FROM  tbl_a a
   where exists ( select a.id1, a.id2 from           
          tbl_c c where ((a.id1 = c.id1 or a.id2 = c.id2)
          AND upper(c.active_flag) = 'Y'))
   and exists ( select a.id1, a.id2 from 
          tbl_b b where  b.id1 = a.id1 or b.id2 = a.id2)
   and exists ( select  a.id1, a.id2 from tbl_d d
               where (a.id1 = d.id1 or a.id2 = d.id2)
               AND d.id3 = 10)

哪个性能最好?我知道查询 2 占用的空间比查询 1 少。但是如何选择最好的呢?

4

3 回答 3

4

选择最好的方法是使用真实数据进行尝试,看看哪个表现最好。如果它们在逻辑上是等效的查询,那么优化器很可能会为两者提供相同的计划,您将能够通过使用 AUTOTRACE 或 TKPROF 或类似工具看到。

于 2009-07-15T12:38:31.130 回答
1

更新

有关性能详细信息,请参阅我的博客中的这篇文章:

这将是最有效的:

SELECT  a.no,
        a.id1,
        a.id2
FROM    tbl_a a
WHERE   EXISTS
        (
        SELECT  1
        FROM    tbl_b b
        WHERE   b.id1 = a.id1
        )
        AND EXISTS
        (
        SELECT  1
        FROM    tbl_c c
        WHERE   c.id1 = a.id1
                AND UPPER(c.flag) = 'Y'
        )
        AND EXISTS
        (
        SELECT  1
        FROM    tbl_d d
        WHERE   d.id1 = a.id1
                AND d.id3 = 10
        )
UNION
SELECT  a.no,
        a.id1,
        a.id2
FROM    tbl_a a
WHERE   EXISTS
        (
        SELECT  1
        FROM    tbl_b b
        WHERE   b.id2 = a.id2
        )
        AND EXISTS
        (
        SELECT  1
        FROM    tbl_c c
        WHERE   c.id2 = a.id2
                AND UPPER(c.flag) = 'Y'
        )
        AND EXISTS
        (
        SELECT  1
        FROM    tbl_d d
        WHERE   d.id2 = a.id2
                AND d.id3 = 10
        )

OracleOR在优化条件方面不太好。

分离查询应该有助于优化器为每个OR'ed 部分使用两个不同的执行计划。

您应该创建以下索引:

tbl_b (id1)
tbl_b (id2)
tbl_c (id1, UPPER(flag))
tbl_c (id2, UPPER(flag))
tbl_d (id1, id3)
tbl_d (id2, id3)

请注意基于函数的索引UPPER(flag),您应该以这种方式创建它。

于 2009-07-15T15:12:10.817 回答
1

没有足够的信息给你一个可靠的答案。有没有索引?对于 TBL_C,有多少百分比的记录具有 FLAG = 'Y' 以及该表中有多少记录?对于表 TBL_D,有多少条 ID3 = 10 的记录?10 是硬编码值还是可以是任何给定的提供值(您将使用绑定变量 - 对吗?)

Tony 关于使用 autotrace 和 tkprof 来查看哪个工作量最少是正确的。我通常从为每个获取一个 SQL_PLAN 开始,如果成本符合我的预期,就运行它们。有了数据量和适当的索引,任何一个都不应运行超过一两秒。

于 2009-07-15T15:53:10.860 回答