Left Outer Join 的条件谓词评估较晚,导致性能问题。甲骨文 8i

Posted

技术标签:

【中文标题】Left Outer Join 的条件谓词评估较晚,导致性能问题。甲骨文 8i【英文标题】:Conditional predicate on Left Outer Join is evaluated late, causing performance problem. Oracle 8i 【发布时间】:2018-12-03 21:06:44 【问题描述】:

这是在 Oracle 8i(抱歉,无法控制)和 php 7 上。

我正在构建一个搜索工具。这是一个包含 3 个字段的简单表单,使用 HTTP Post 方法。然后 PHP 对 3 个字段的值进行一些检查,确定它们是否有效,然后将值发送到 SQL 查询。查询看起来像这样;记住它的 8i,所以这里没有 ANSI 加入:

SELECT
reports_table.*, documents_table.*, cases_table.*

FROM
reports_table, documents_table, cases_table

WHERE
reports_table.report_id = documents_table.report_id
AND reports_table.report_id = cases_table.report_id(+)

-- Report Number filtering

    AND reports_table.report_no = 
        CASE
            WHEN $report_no_isvalid = 1
            THEN '$report_no'       -- Oracle expects datatype varchar2
            ELSE reports_table.report_no
        END

-- Document Number filtering

    AND documents_table.document_no = 
        CASE
            WHEN $doc_no_isvalid = 1
            THEN $doc_no        -- Oracle expects datatype number
            ELSE documents_table.document_no
        END

-- Case Number filtering

    AND cases_table.case_no = 
        CASE
            WHEN $case_no_isvalid = 1
            THEN '$case_no'     -- Oracle expects datatype varchar2
            ELSE cases_table.case_no
        END

要求用户至少输入一个报告编号或案例编号。需要完整的数字,即不允许通配符搜索。 reports_table 非常大。 按Report Number搜索时,数据库耗时很长,好像作用于Report Number有效性的CASE评估,即这里这段代码

AND reports_table.report_no = 
    CASE
        WHEN $report_no_isvalid = 1
        THEN '$report_no'       -- Oracle expects datatype varchar2
        ELSE reports_table.report_no
    END

在加入操作之后被评估。虽然它似乎确实被评估了,因为如果我在 WHERE 子句中添加另一个简单的谓词来限制报告编号的范围,数据库会非常快速地回答,并得到预期的结果。例如假设我正在搜索的报告编号是“R123456”,如果我添加AND reports_table.report_no LIKE 'R1234%',作为 CASE 语句之外的谓词,则性能很好。否则它会非常慢,好像 Oracle 正在扫描整个 reports_table 以尝试进行连接。

我想找到一种方法来告诉 Oracle 以确保它在执行联接时查看报告编号上的条件 CASE 过滤器,但我不知道如何。 或者也许我应该完全避免这种对连接的条件限制,如果是这样,我可以使用什么技术来实现我想要做的事情?

【问题讨论】:

【参考方案1】:

自从我不得不处理这个问题已经有一段时间了:并且完全在黑暗中射击......是否重新安排限制以便在外部连接之前强加它们?

WHERE
(reports_table.report_id = documents_table.report_id
-- Report Number filtering

    AND reports_table.report_no = 
        CASE
            WHEN $report_no_isvalid = 1
            THEN '$report_no'       -- Oracle expects datatype varchar2
            ELSE reports_table.report_no
        END
-- Document Number filtering
    AND documents_table.document_no = 
        CASE
            WHEN $doc_no_isvalid = 1
            THEN $doc_no        -- Oracle expects datatype number
            ELSE documents_table.document_no
        END)
AND 
(reports_table.report_id = cases_table.report_id(+)
-- Case Number filtering
    AND cases_table.case_no = 
        CASE
            WHEN $case_no_isvalid = 1
            THEN '$case_no'     -- Oracle expects datatype varchar2
            ELSE cases_table.case_no
        END)

我知道在 ANSI 中,如果我在使用外连接的表的 where 中使用 AND,我的外连接的行为类似于内连接。我想知道如果重新安排引擎是否会更好地优化;或者是否需要实际的 SQL 提示。

【讨论】:

以上是关于Left Outer Join 的条件谓词评估较晚,导致性能问题。甲骨文 8i的主要内容,如果未能解决你的问题,请参考以下文章

LEFT OUTER JOIN 不能在没有连接两边的字段相等的条件下使用

熊猫:LEFT OUTER JOIN where(ON)2个匹配的条件[重复]

将非 FK 条件添加到 Django ORM 中的 LEFT OUTER JOIN 以返回不连接的行

LEFT OUTER JOIN 在 bigquery 上创建子查询时出错

SQL 查询条件放在LEFT OUTER JOIN 的ON语句后与放在WHERE中的区别

Oracle表与表之间的连接方式(内连接:inner join 外连接 全连接: full outer join左连接:left outer join 右连接:right outer join(代码