Oracle WITH子句限制

时间:2019-06-03 07:40:22

标签: sql oracle oracle12c

我有一个非常复杂的查询,该查询基于将多个表联合在一起。目前,我们正在使用视图来对所需的所有行执行操作,因此视图和查询如下所示:

CREATE VIEW
    V_VIEW
    (
        COL1, COL2, COL3, COL4
    ) AS
SELECT
    "COL1", "COL2", "COL3", "COL4"
FROM
    TABLE1
UNION ALL
SELECT
    "COL1", "COL2", "COL3", "COL4"
FROM
    TABLE2;

SELECT
        COL1, COL2
FROM
    (   SELECT
            COL1, COL2
        FROM
            V_VIEW
        WHERE
            COL1 like 'val%'
        AND COL2 =
            (
                SELECT
                    MAX(COL3)
                FROM
                    V_VIEW
                WHERE
                    COL4 = 'Y' ) part1
UNION ALL
SELECT
        COL1, COL2
FROM
    (   SELECT
            COL1, COL2
        FROM
            V_VIEW
        WHERE
            COL1 like 'sth%'
        AND COL2 =
            (
                SELECT
                    MIN(COL3)
                FROM
                    V_VIEW
                WHERE
                    COL4 = 'N' ) part2;

我正在寻找一种提高此查询性能的方法,不幸的是,目前无法创建由Table1和Table2的所有行组成的新表(我们不允许干预其中插入行的方式) )。我尝试使用WITH子句代替视图,因此看起来有点像:

WITH TEMP_TABLE AS (
SELECT
    COL1, COL2, COL3, COL4
FROM
    TABLE1
UNION ALL
SELECT
    COL1, COL2, COL3, COL4
FROM
    TABLE2 )
SELECT
        COL1, COL2
FROM
    (   SELECT
            COL1, COL2
        FROM
            TEMP_TABLE
        WHERE
            COL1 like 'val%'
        AND COL2 =
            (
                SELECT
                    MAX(COL3)
                FROM
                    TEMP_TABLE
                WHERE
                    COL4 = 'Y' ) part1
UNION ALL
SELECT
        COL1, COL2
FROM
    (   SELECT
            COL1, COL2
        FROM
            TEMP_TABLE
        WHERE
            COL1 like 'sth%'
        AND COL2 =
            (
                SELECT
                    MIN(COL3)
                FROM
                    TEMP_TABLE
                WHERE
                    COL4 = 'N' ) part2

在较小的数据量(表1和表2具有约2万行)上,这可以很好地提高性能。但是,这些表最终将塞满数百万行。我不完全了解WITH子句的处理方式,所以我想知道:使用WITH闭包的查询是否有可能在大量数据上失败(由于缺少内存?),而没有它的查询会不会失败?会工作缓慢,但会很好吗?

3 个答案:

答案 0 :(得分:1)

您可以尝试使用以下内容:

WITH main_res AS (SELECT col1,
                         col2,
                         MAX(CASE WHEN col4 = 'N' THEN col3) OVER () col3_n_max,
                         MAX(CASE WHEN col4 = 'Y' THEN col3) OVER () col3_y_max
                  FROM   v_view
                  WHERE  col1 LIKE 'val%'
                  OR     col1 LIKE 'sth%')
SELECT col1,
       col2
FROM   main_res
WHERE  (col1 LIKE 'val%' AND col2 = col3_y_max)
OR     (col1 LIKE 'sth%' AND col2 = col3_n_max);

这使用条件最大解析函数返回所有行中的最大值(取决于col4值)。

一旦您知道了这些信息,就可以对其进行适当的过滤。这样可以减少查询每个表的次数,通常比原始查询要快(但不总是如此!)。我建议您测试一下该查询,并确定它是否比原始查询(以及其他任何答案)更快,然后再选择要使用的查询。

答案 1 :(得分:1)

WITH子句是一种动态创建的VIEW,使用时不会将其代码存储在DB中。但是,它消耗主内存来存储与游标有关的信息,该游标用于从WITH SELECT查询中检索行。你是对的;对具有大量数据的表进行查询将减慢数据库速度。

我不知道: a)TABLE1和TABLE2是否保存完整的数据集,或者这些表是增量更新的。 b)此表中是否有日期列? c)这些表以什么间隔填充或更新?

基于上述问题的答案: 与您的DBA讨论之后:

  1. 您可以要求DBA从TABLE1和TABLE2中提取属于TRUNC(SYSDATE)或TRUNC(SYSDATE)-1的数据,并将此数据填充到具有相同列以及两个附加列的单个“新”表中: a)一列将包含COL1值的前三个字母。 b)另一列用于保存状态值的默认值“ Q”。
  2. 在此新表上的COL1上为值“ Val”和“ Sth”创建一个LIST分区,并为Y和N创建值COL4。
  3. 写一个匿名块,该匿名块按所需方式准备数据。然后,对该新表进行简单查询即可为您获取数据。我们可以根据源表TABLE1和TABLE2中数据可用的频率,在作业调度中调度此匿名块。

这些建议基于一组假设和您共享的信息量。

如果该数据上正在运行任何UI或报表,则需要保留此数据。

底线:

  1. 根据后续过程的要求预先准备数据,而不是在需要时即时准备数据。这样可以简化您的整个过程,也可以查询一部分。
  2. 在Prod或Int环境中遇到性能瓶颈的大多数时候,我们总是在寻找短期解决方案。解决当前问题非常需要短期解决方案。但是,我建议您也准备长期解决方案。

答案 2 :(得分:0)

在花费大量时间进行重写之前,确保优化器有做好工作的机会是有帮助的。确保表格具有良好的统计信息和适当的索引。

针对您的查询运行说明计划,以查看Oracle在每种情况下实际在做什么。您可能会发现那些UNION ALL语句正在发生意外情况。优化器有时会做出愚蠢的决定,您可能需要通过索引或策略性应用提示来帮助它。

WITH子句非常方便,并且与独立视图或在表列表中内联定义的视图执行相同的工作,但有一个关键的例外:Oracle在独立视图,WITH子句视图和内联视图中对独立视图的处理略有不同。优化过程。 Oracle可以选择实现在WITH子句中定义的视图的结果,而如果是内联定义的,它可以合并视图。

问题在于,在查询中的这三种视图之间进行更改将导致优化器的细微差别开始显示。

最后,您使用的是什么版本的Oracle?优化器是版本真正重要的领域。