为什么两个数字的 UNION 比它们的总和更有效?

Why is a UNION on two numbers more efficient than their sum?

我们要确保一个位置(具有特定类型的库存)的调色板不超过 maxCount 个。 为了确保这一点,我们总结了其上带有调色板的位置或调色板将位于的位置。两种说法都可以正常工作。但是,我的初稿表现不佳。我的导师想出了一个不同的草稿,速度要快得多,但他无法解释原因。

慢语句:

 AND maxCount > ( 
    SELECT 
        trptoloc+atloc
    FROM
        (
            SELECT
                COUNT(DISTINCT loc2.locnam) AS atloc
            FROM
                loc_t loc2,
                pal_t pal,
                inv_t inv,
                art_t art
            WHERE
                loc.group = loc2.group
                AND   pal.locnam = loc2.locnam
                AND   inv.palnam = pal.palnam
                AND   inv.artid = art.artid
                AND   AND   art.feature = value
        ),
        (
            SELECT
                COUNT(DISTINCT loc2.locnam) AS trptoloc
            FROM
                trp_t trp,
                loc_t loc2,
                inv_t inv,
                art_t art
            WHERE
                trp.locnamezl = loc2.locnam
                AND   trp.palnam = inv.palnam
                AND   loc.group = loc2.group
                AND   inv.artid = art.artid
                AND   art.feature = value;
        )
)

更快的语句:

AND maxCount > (
 SELECT
 SUM(invpal)
 FROM
 (SELECT
    COUNT(distinct inv.palnam) AS invpal
    FROM
        inv_t inv,
        art_t art,
        pal_t pal,
        loc_T loc2
    WHERE
        inv.artid = art.artid
        AND   loc.group = loc2.group
        AND   pal.locnam = loc2.locnam
        AND   inv.palnam = pal.palnam
        AND   art.feature = value;
  UNION ALL
    SELECT COUNT(distinct inv.palnam) AS invpal
    FROM
        inv_t inv,
        art_t art,
        trp_t trp,
        loc_T loc2
    WHERE
        trp.locnamezl = loc2.locnam
        AND   trp.palnam = inv.palnam
        AND   loc.group = loc2.group
        AND   inv.artid = art.artid
        AND   art.feature = value;
)
)

任何有助于我理解性能差异的提示或 link 都非常感谢!

您的第一个示例是加入两个内联视图。这不一定是坏事,但如果你看一下解释计划,Oracle 可能正在对这两个视图进行嵌套循环,这意味着它将它们分别加载到内存中,然后将它们连接在一起(什么都没有 - 这是一个 cross/cartesian加入)。

在 UNION ALL 示例中,优化器不必执行任何复杂的操作 - 它只运行前半部分,然后运行后半部分,然后对两行求和。它不会尝试将两个查询同时保存在内存中,以便将它们相互比较。

作为旁注,there are often ways to rewrite inline views to perform better,尽管它会使您的代码更难理解。你没有给我们很多关于你的 table 结构或数据的细节,但我认为你可以重写这个查询,这样它只读取每个 table 一次而不是两次,例如

AND maxCount > (
  select count(distinct inv.palnam)
  from inv_t inv
  join art_t art 
        on inv.artid = art.artid and art.feature = value
  join loc_T loc2 
        on loc.group = loc2.group
  left join pal_t pal 
        on pal.locnam = loc2.locnam
        and pal.palnam = inv.palnam 
  left join trp_t trp 
        on trp.palnam = inv.palnam
        and trp.locnamezl = loc2.locnam
  where pal.palnam is not null or trp.palnam is not null
)

我还重写了它以使用显式 ANSI 连接,就像 Gordon 所建议的那样。