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(代码