【问题标题】:Oracle performance and memoryOracle 性能和内存
【发布时间】:2010-11-10 23:39:51
【问题描述】:

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

查询 1:

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 少。 但是如何选择最好的呢?

【问题讨论】:

    标签: performance oracle join exists


    【解决方案1】:

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

    【讨论】:

    • 嗨托尼,我的错误是……我错过了括号。我现在已经更新了查询,在我的情况下是((a 或 b)和 c)。
    • 好的,我已经删除了关于括号的 cmets。现在我也很高兴这两个查询在逻辑上是等价的。
    【解决方案2】:

    更新:

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

    这个效率最高:

    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
            )
    

    Oracle 在优化OR 条件方面不太好。

    分离查询应该有助于优化器对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) 上的基于函数的索引,您应该以这种方式创建它。

    【讨论】:

    • 您更改了查询 - ('y','Y') != ('Y') 联合导致对返回的结果集进行排序。第一个选择缺少“AND d.id3 = 10”
    • @glenn:原来查询说UPPER(flag) = 'Y',相当于flag IN('y', 'Y')
    • @glenn: UNION 不一定会导致排序,这取决于优化器选择的方法:SORT UNIQUE 或 HASH UNIQUE,后者不会排序
    【解决方案3】:

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

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

    【讨论】:

    • 有足够的信息表明需要哪些索引。
    • 确定吗?桌子有多大?我们知道记录的数量,但不知道它们有多大。 FLAG 字段是否在 1% 或 99% 的记录上设置为是? TBL_D 也一样?当他们应该使用完全扫描时,我遇到了更多使用索引的查询问题,然后反过来。索引并不邪恶,但它们也不能解决所有问题。
    猜你喜欢
    • 2018-04-17
    • 1970-01-01
    • 2013-05-09
    • 2015-12-22
    • 2020-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-21
    相关资源
    最近更新 更多