提高Oracle视图的性能

时间:2013-02-12 17:19:25

标签: optimization view oracle10g query-optimization

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

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子查询中?

2 个答案:

答案 0 :(得分:2)

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

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

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

  • 如果您有一个基本表,其主键是您最终要过滤视图的内容,请尝试进行设置,以便您的视图的主查询从该开始,然后加入到您的复杂的子句查询,即使该连接完全是冗余的(即,在加入复杂的位之前,给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查询并不总是一个合理的过程。

答案 1 :(得分:0)

您可以使用此处描述的上下文参数:creating parameterized views in 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中的参数(e)rized视图”)...