Oracle 是不是关联嵌套在任何级别的子查询?

Posted

技术标签:

【中文标题】Oracle 是不是关联嵌套在任何级别的子查询?【英文标题】:Does Oracle correlate a subquery nested at any level?Oracle 是否关联嵌套在任何级别的子查询? 【发布时间】:2016-05-19 13:20:34 【问题描述】:

我看到这个论坛关于同一主题的不同问题,一个固定且经常出现的回答是:

不,Oracle 不会关联嵌套超过一层的子查询(mysql 也不会)。

我会由此得出结论,Oracle 确实将子查询关联到一个更深的层次。但是,我有以下查询,它返回此错误消息:

ORA-00904: "CD"."FIELD6": 标识符无效

这个查询很重要,要按原样进行设计,它只是涉及 UNION 语句的实际查询的简化版本。在调试返回错误消息的原因时,我将其简化为最简单的版本(如下)。我意识到对于这个最简单的版本可能有替代的 JOIN 方法,但这种替代方法不会在实际查询中发挥作用。如果下面可以工作,那么看起来我们更复杂的查询也可以工作。如果以下内容不起作用,那么我在 Oracle 的文档和上面的“罐头”答案中读错了什么?

SELECT a.*
FROM
    main_detail cd INNER JOIN
    (
    SELECT
        Field1,
        Field2,
        Field3,
        Field4,
        Field5,
        Field6,
        Field7
    FROM other_detail x2
    WHERE x2.Field1 = cd.Field1 AND x2.Field6 = cd.Field6
    ) a ON
    a.Field1 = cd.Field1
    AND a.Field4 = cd.Field4
    AND a.Field6 = cd.Field6

下面更接近我们的实际需要。 UNION 需要按原样允许返回的 UNION-ed 集上的 JOIN,它被用作 INNER JOIN 以限制返回记录集:

SELECT h.*, a.*
FROM
    header h,
    (
    SELECT
        Field1,
        Field2,
        Field3,
        Field4,
        Field5,
        Field6,
        Field7
    FROM main_detail x1
    WHERE x1.Field1 = h.Field1 AND x1.Field6 = h.Field6
    UNION
    SELECT
        Field1,
        Field2,
        Field3,
        Field4,
        Field5,
        Field6,
        Field7
    FROM other_detail x2
    WHERE x2.Field1 = h.Field1 AND x2.Field6 = h.Field6
    ) a
    WHERE
        a.Field1 = h.Field1 AND
        a.Field6 = h.Field6

对比上述不包括相关子查询参数,并在MS SQL中测试运行,性能从9分钟提升到30-40秒,提升非常可观。我希望在 Oracle 中也能体验到同样的收获。

在不损害客户机密性的情况下,以下是我可以为实际代码所做的尽可能接近的内容:

SELECT DISTINCT 
    c.Field1,
    c.Field2,
    D.Field3,
    b.Field4,
    b.Field5,
    c.Field6,
    c.Field7 || '-' || cds1.Field8 AS status,
    b.paid,
    cds.Field8,
    p.Field9,
    p.Field10,
    c.Field11,
    c.Field12 AS provider_name
FROM
    header c,
    (
    SELECT
        a.*,
        cd.paid,
        cd.Field15,
        cd.BigList,
        cd.allowed,
        cd.copayment,
        cd.coinsurance
    FROM
        header_detail cd,
        (
        SELECT
            Field1,
            Field4,
            '' AS revenue_code,
            Field20,
            Field5,
            Field14,
            location_code,
            ServiceList
        FROM header_other_detail x1
        WHERE x1.Field1 = cd.Field1 AND x1.Field14 = cd.Field14
        UNION
        SELECT
            Field1,
            Field4,
            revenue_code,
            Field20,
            Field5,
            Field14,
            '' AS location_code,
            ServiceList
        FROM inst_claim_detail x2
        WHERE x2.Field1 = cd.Field1 AND x2.Field14 = cd.Field14
        ) a
    WHERE
        a.Field1 = cd.Field1
        AND cd.Field1 = c.Field1
        AND a.Field20 = cd.Field20
        AND a.Field14 = cd.Field14
        AND cd.Field14 = c.Field14a
    ) b,
    (
    SELECT
        Field1,
        Field14,
        Trim(
            Trailing ',' FROM
            ch.icd9_1  || ',' ||
            ch.icd9_2  || ',' ||
            ch.icd9_3  || ',' ||
            ch.icd9_4  || ',' ||
            ch.icd9_5  || ',' ||
            ch.icd9_6  || ',' ||
            ch.icd9_7  || ',' ||
            ch.icd9_8  || ',' ||
            ch.icd9_9  || ',' ||
            ch.icd9_10 || ',' ||
            ch.icd9_11 || ',' ||
            ch.icd9_12
            )
        AS Field3
    FROM prof_claim ch
    WHERE ch.Field1 = c.Field1 AND ch.Field14 = c.Field14a
    UNION
    SELECT
        Field1,
        Field14,
        Field3
    FROM inst_claim x3
    WHERE x3.Field1 = c.Field1 AND x3.Field14 = c.Field14a
    ) d,
    (
    SELECT
        Field1,
        Field14,
        Field9,
        Field10,
        Field18,
        refund_amount,
        Field15
    FROM payment_detail
    ) p,
    (SELECT * FROM Codes WHERE code_type='19') cds,
    (SELECT * FROM Codes WHERE code_type='28') cds1
WHERE
    c.Field17 = 'T00000370'
    AND c.Field1 = b.Field1 AND c.Field14a = b.Field14
    AND c.Field1 = d.Field1 AND c.Field14a = d.Field14
    AND b.Field14 = p.Field14(+) AND b.Field1 = p.Field1(+) AND b.Field15 = p.Field15(+)
    AND b.BigList = cds.Field16(+) AND b.Field14 = cds.Field14(+)
    AND c.Field7 = cds1.Field16(+) AND c.Field14a = cds1.Field14(+)
ORDER BY Field1;

【问题讨论】:

Oracle 12c 支持超过一层深度的关联。所有之前的版本都只有一个级别。 【参考方案1】:

在子查询中

SELECT
    Field1,
    Field2,
    Field3,
    Field4,
    Field5,
    Field6,
    Field7
FROM other_detail x2
WHERE x2.Field1 = cd.Field1 AND x2.Field6 = cd.Field6

检查 where 条件。如果完全删除或至少删除 cdreference - 查询有效。

【讨论】:

【参考方案2】:

如果您要将子查询连接到表(或另一个子查询),那么所有连接条件都必须在 ON 子句中,如果您使用的是 ANSI 样式连接。

您的查询失败的原因是a 子查询的范围没有扩展到自身之外。它与 main_detail 表的范围完全分开,因为您尝试加入这些表,而不是关联它们。正如 Marmite Bomber 的回答所暗示的那样,子查询需要能够自行运行,而您尝试的版本不能。

您需要做的是将相关过滤器移至ON 子句,如下所示:

SELECT a.*
FROM
    main_detail cd INNER JOIN
    (
    SELECT
        Field1,
        Field2,
        Field3,
        Field4,
        Field5,
        Field6,
        Field7
    FROM other_detail x2) a ON
    a.Field1 = cd.Field1
    AND a.Field4 = cd.Field4
    AND a.Field6 = cd.Field6
    and a.Field1 = cd.Field1 AND a.Field6 = cd.Field6

当然,等同于:

SELECT a.*
FROM
    main_detail cd INNER JOIN
    other_detail a ON
      a.Field1 = cd.Field1
      AND a.Field4 = cd.Field4
      AND a.Field6 = cd.Field6

关于您使用 UNION 的查询,这应该有助于您在原始查询中获得一些性能优势:

SELECT *
FROM   (SELECT h1.*,
               x1.field1,
               x1.field2,
               x1.field3,
               x1.field4,
               x1.field5,
               x1.field6,
               x1.field7
        FROM   main_detail x1
               inner join header h1 on (x1.Field1 = h1.Field1 AND x1.Field6 = h1.Field6)
        UNION
        SELECT h2.*
               field1,
               field2,
               field3,
               field4,
               field5,
               field6,
               field7
        FROM   other_detail x2
               inner join header h2 on (x2.Field1 = h2.Field1 AND x2.Field6 = h2.Field6));

【讨论】:

我已经用替代建议更新了我的答案。出于好奇,您的标题和详细信息表中有多少行?此外,您是否希望从主表和其他详细表中返回相同的数据?因为如果数据是完全分离的,那么您可以使用 UNION ALL 并为自己保存一个 sort/distinct 操作。 很好,但实际查询有 8 个子选择表和 5 个主表,因此在不丢失 UNION 的完整性的情况下无法轻松完成连接,以作为针对主表的限制条件桌子。因此,UNION 是其他 4 个类似的 UNION 之一。如上面编辑过的帖子所示,在 MS SQL 中进行测试时,性能从 9 分钟变为 30-40 秒。它在 Oracle 中的运行时间非常相似,大约为 9 分钟。我们希望获得与 MS SQL 一样的优势。 如果您可以使用更准确地反映您的实际查询的示例查询来更新您的问题,我们或许可以提出您可以做出的改进建议。 页眉超过 4 亿行,细节超过 14 亿行。因此,为什么我也很快变得讨厌 Oracle 不允许我在明细表的 Header_ID 字段上设置聚集索引。在 MS SQL 中管理表的聚集索引是传统上使我在优化数据库时成为超级明星的“魔法”。 一个快速的谷歌揭示:dba.stackexchange.com/questions/7951/… - 也许在 Oracle 中将头表重新创建为 IOT 可能会给您带来一些额外的性能优势?这是假设 header 不是一个宽表。

以上是关于Oracle 是不是关联嵌套在任何级别的子查询?的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 之 子查询与嵌套查询

oracle嵌套关联子查询问题

6-SQL子查询

(oracle)子查询和关联查询效率问题

oracle子查询问题,急急急!

mysql 关联查询是不是很耗性能