提高 Oracle 视图的性能

Posted

技术标签:

【中文标题】提高 Oracle 视图的性能【英文标题】:Improving performance on an Oracle view 【发布时间】:2013-02-12 17:19:24 【问题描述】:

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

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

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

此查询的执行包括全表扫描。这是有道理的,因为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 子查询中?

【问题讨论】:

当你说你没有在 WITH 子句内的子查询中指定 WHERE 条件的选项时,你是什么意思? @Darius - 如果我想将我的视图限制在某个数据子集,我确实可以在我的视图中指定一个WHERE 条件。这不是我想要的。 @Darius - 我说的是,如果针对视图的查询,向该查询添加WHERE 条件不会将其放在执行计划中的正确位置。 (注意WITH 子查询中的WHERE 条件是我在视图之外修复执行计划的方式)。 感谢您的澄清。您是否尝试过在最终 SQL 上使用全局提示,通过在此处命名视图? docs.oracle.com/cd/B10500_01/server.920/a96533/… 谢谢,大流士 (+1)。这可能正是我想要的,但如果不知道“全局提示”这个短语就很难找到。 【参考方案1】:

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

运行“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 查询并不总是一个合理的过程。

【讨论】:

非常感谢,伊万。事实证明,您的提示非常有帮助,尤其是第 3 点和第 5 点(如果它们已被编号)。【参考方案2】:

您可以使用如下所述的上下文参数:creating parameterized views in oracle11g 或http://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 */

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

【讨论】:

以上是关于提高 Oracle 视图的性能的主要内容,如果未能解决你的问题,请参考以下文章

oracle 视图

Oracle物化视图

Oracle 物化视图

oracle物化视图

Oracle视图 create View

Oracle普通视图和物化视图的区别