2

我有一个要保存为视图的查询:

WITH subquery AS ( SELECT aaa_id, ... FROM table_aaa ... )
SELECT subquery.aaa_id, ... FROM table_bbb JOIN subquery USING ( ... )
;

[注意:在现实生活中,我的查询比这复杂得多,有几个WITH子查询,许多正在执行JOINS,都被JOIN一起编辑。但我正在寻找可以用来解决我的问题的一般指导。]

此查询的执行包括全表扫描。这是有道理的,因为WHERE子句中不包含任何标准。但是,我可以通过包含这样一个子句来消除大多数全表扫描:

WITH subquery AS ( SELECT aaa_id, ... FROM table_aaa ... WHERE aaa_id = :id)
SELECT subquery.aaa_id, ... FROM table_bbb JOIN subquery USING ( ... )
;

WHERE但是,当我创建视图时,我似乎无法选择将条件放在正确的位置:

CREATE OR REPLACE VIEW vw_my_view AS
WITH subquery AS ( SELECT aaa_id, ... FROM table_aaa ... )
SELECT subquery.aaa_id, ... FROM table_bbb JOIN subquery USING ( ... )
;

SELECT ... FROM vw_my_view WHERE aaa_id = :id
;

在这种情况下,执行计划仍然包含全表扫描。有没有办法让我暗示该WHERE子句实际上可以插入到WITH子查询中?

4

2 回答 2

2

我有过类似的经历,虽然我没有通用的解决方案,但我建议如下:

  • 运行“SELECT * FROM v$parameter2;” 并确保 _complex_view_merging 已打开。在与它相关的早期 10g 版本之一中存在一个令人讨厌的错误,因此一些 dbas 将其关闭,并且可能在修复后忘记将其重新打开。

  • 将所有关于提示的考虑作为最后的措施。根据我的经验,它们对于防止全表扫描很少有用,因为优化器已经尽其所能避免它们。

  • 如果您有一个基表,其主键是您最终要过滤视图的内容,请尝试进行设置,以便您的视图的主查询以该表开头,然后加入您复杂的 with 子句查询,即使那join 是完全多余的(即让 oracle 有机会在加入复杂位之前对该基表进行简单过滤)。确保将要过滤视图的列是直接从该基表中选择的,而不是从 complex_query 中选择的。所以像

.

     with (complicated_query)
     select base_table.key1, complicated_query.*
     from base_table
     join complicated_query on base_table.key1 = complicated_query.key1;
  • 如果您有使用不相关子查询的过滤器,请尝试将它们切换为相关等价物(反之亦然)。

  • 在 FROM 子句中使用连接语句的顺序和/或从哪个表开始,即使从逻辑上讲它不会对结果产生影响。这是一个有点绝望的策略,但通过这样做,我确实让执行计划变得更好。优化 Oracle 查询并不总是一个合理的过程。

于 2013-02-13T22:32:57.397 回答
0

您可以使用此处描述的上下文参数:在 oracle11ghttp://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:906341500346611919中创建参数化视图 (“参数化视图 - vs- 带有 where 条件的视图”,以防他们再次更改 URL)

这样,您可以将 WHERE aaa_id = SYS_CONTEXT ('my_namespace', 'aaa_id') 放在视图定义的深处,并像这样使用它:

CREATE OR REPLACE VIEW vw_my_view AS
WITH subquery AS ( SELECT aaa_id, ... FROM table_aaa ...
   WHERE aaa_id = SYS_CONTEXT ('my_namespace', 'aaa_id'))
SELECT subquery.aaa_id, ... FROM table_bbb JOIN subquery USING ( ... )
;

DBMS_SESSION.SET_CONTEXT('my_namespace', 'aaa_id', TO_CHAR(:id));
SELECT ... FROM vw_my_view  /* this is not needed any more: WHERE aaa_id = :id */

谷歌获取更多示例和解释(搜索术语“oracle 中的参数(电子)化视图”)...

于 2013-10-19T18:48:08.627 回答