【问题标题】:poor performance of view built on base views基于基础视图构建的视图性能不佳
【发布时间】:2016-06-21 19:22:49
【问题描述】:

我有一个 Oracle 视图(使用 11gR2),它是其他三个视图的连接,即:

create or replace view main_vw as
select a.*, b.*, c.*
from a_vw a, b_vw b, c_vw c
where a.b_id = b.b_id
and a.c_id = c.c_id

执行“select * from main_vw”会挂几个小时,而 EXPLAIN PLAN 显示了一个非常低效的查询计划。但是,如果创建逻辑上等效的步骤:

create table a_tbl as select * from a_vw;
create table b_tbl as select * from b_vw;
create table c_tbl as select * from c_vw;
select a.*, b.*, c.*
from a_tbl a, b_tbl b, c_tbl c
where a.b_id = b.b_id and a.c_id = c.c_id;

所有四个语句在 5 秒内完成。

有什么方法可以使用提示或其他东西让 Oracle 的优化器首先评估子视图,然后像表格一样加入它们?

我查看了提示“QB_NAME”、“NO_EXPAND”、“NO_REWRITE”,但无济于事......

注意:本例中的 a_vw、b_vw 和 c_vw 是相当复杂的查询,它们共同引用基表。它们还引用了一个设置表,其内容在会话级别进行自定义并影响返回的内容。因此,我无法从这些视图创建表。

【问题讨论】:

    标签: oracle plsql oracle11g query-optimization


    【解决方案1】:

    使用ROWNUM 强制Oracle 独立评估内联视图。

    create or replace view main_vw as
    select a.*, b.*, c.*
    from
      (select * from a_vw where rownum >= 1 /*prevent transformations*/) a,
      (select * from b_vw where rownum >= 1 /*prevent transformations*/) b,
      (select * from c_vw where rownum >= 1 /*prevent transformations*/) c
    where a.b_id = b.b_id
    and a.c_id = c.c_id
    

    起初这看起来很奇怪。 ROWNUM 似乎没有做任何事情。但是ROWNUM 是一个特殊的用于排序的伪列,“会影响视图优化”。实际上,它会阻止所有优化,并且是完全隔离代码的唯一安全方法。此方法对于类型安全也很有用,例如 Entity-Attribute-Value 模式,其中所有内容都存储为字符串,并且必须按特定顺序进行处理。

    正如您已经发现的那样,提示很难做到正确。即使您现在确实得到了它们,将来当另一个开发人员修改查询时,它们也很有可能无法正常工作。为了防止他们删除这个神秘的谓词,请务必添加评论。

    这不一定能解决根本的性能问题,但至少应该让它更容易解决。总体解释计划应包括与每个内联视图的解释计划相匹配的三个部分。如果每个内联视图运行良好,您只需要担心它们之间的两个连接。

    【讨论】:

    • 您好约翰,非常感谢您的回复。我试过了,确实,在使用ROWNUM >= 1 条件后,EXPLAIN PLAN 看起来好多了,命中索引而不是进行全表扫描。奇怪的是,即使有这个有希望的EXPLAIN PLAN,查询本身也需要 7 分钟才能完成。当我改为为三个单独的视图中的每一个执行CREATE TABLE AS SELECT ,然后使用这三个表进行查询时,整个过程仍然需要不到一秒钟的时间。 ;(
    • 这三个查询各自运行得很快吗?也许只有其中一个有问题。 (并确保您正在比较返回所有行的时间,而不仅仅是第一个 N。)
    • 是的,“整个过程”是指四个 CTAS 语句。前三个是CREATE TABLE A_TAB AS SELECT * from A_VW等,然后是CREATE TABLE MAIN_TAB AS SELECT a.*, b.*, c.* from A_TAB A, B_TAB B, C_TAB C where A.B_ID = B.B_ID and A.C_ID = C.C_ID我这样做是为了减少打印/网络时间的测量。
    • 也许加入这三个内联视图的计划很糟糕;尽管单个内联视图可能运行得很快,但整个计划可能会运行很多次。也许在三个视图之间的解释计划部分中有一个MERGE JOIN CARTESIAN?如果查询很复杂,这可能是使用提示的时候了。优化器通常会低估大型查询的行数。如果您知道实际的行数,请为某些内联视图尝试类似 ` ... (select /*+ cardinality(2000) */ ...` (将 2000 替换为实数)之类的提示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-08
    • 2012-06-01
    • 2016-03-06
    • 2020-11-30
    • 2013-01-25
    • 1970-01-01
    相关资源
    最近更新 更多