【问题标题】:(Oracle Performance) Will a query based on a view limit the view using the where clause?(Oracle 性能)基于视图的查询是否会使用 where 子句限制视图?
【发布时间】:2010-03-22 19:03:27
【问题描述】:

在Oracle(10g)中,当我使用视图(不是物化视图)时,Oracle在执行视图时是否考虑到where子句?

假设我有:

MY_VIEW =
SELECT * 
FROM PERSON P, ORDERS O
WHERE P.P_ID = O.P_ID

然后我执行以下操作:

SELECT * 
FROM MY_VIEW
WHERE MY_VIEW.P_ID = '1234'

执行此操作时,oracle 是否首先执行视图查询,然后根据我的 where 子句(其中 MY_VIEW.P_ID = '1234')对其进行过滤,还是在执行视图时执行此过滤?如果它不执行后者,并且 P_ID 有索引,我是否也会失去索引功能,因为 Oracle 将针对没有索引的视图而不是具有索引的基表执行我的查询?

【问题讨论】:

  • 当您说索引时,您在说哪个索引 1. PERSON 中的 P_ID 2. ORDERS 中的 P_ID 3. MY_VIEW 中的 P_ID .. 我在下面的答案中假设 #3 并且您无法在其上创建索引逻辑观点。你会得到 ORA-01702 错误

标签: sql oracle views


【解决方案1】:

它不会先执行查询。如果您在P_ID 上有索引,则会使用它。

执行计划与将视图代码和WHERE-clause 合并到单个选择语句中一样。

你可以自己试试:

EXPLAIN PLAN FOR
SELECT * 
FROM MY_VIEW
WHERE MY_VIEW.P_ID = '1234'

紧随其后

SELECT * FROM TABLE( dbms_xplan.display );

---------------------------------------------------------------------------------
|Id | Operation                    | Name   |Rows| Bytes | Cost (%CPU)| Time    |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT             |        |  1 |    52 |     2   (0)| 00:00:01|
| 1 |  NESTED LOOPS                |        |  1 |    52 |     2   (0)| 00:00:01|
| 2 |   TABLE ACCESS BY INDEX ROWID| PERSON |  1 |    26 |     2   (0)| 00:00:01|
| 3 |    INDEX UNIQUE SCAN         | PK_P   |  1 |       |     1   (0)| 00:00:01|
| 4 |   TABLE ACCESS BY INDEX ROWID| ORDERS |  1 |    26 |     0   (0)| 00:00:01|
| 5 |    INDEX RANGE SCAN          | IDX_O  |  1 |       |     0   (0)| 00:00:01|
---------------------------------------------------------------------------------

【讨论】:

  • 您可以通过查看说明计划或在 SQLplus 中打开自动跟踪来轻松证明这一点。
【解决方案2】:

哇!这很有趣..我有两个不同的解释计划取决于不同的数据量和逻辑视图中的查询(这是我的假设)

  1. 原题案例:肯定是先做过滤。 我在这个测试表中有少量数据(总共 ` | 0 | SELECT STATEMENT | | 2 | 132 | 2 (0)| 00:00:01 | | 1 | NESTED LOOPS | | 2 | 132 | 2 (0)| 00:00:01 | | 2 | TABLE ACCESS BY INDEX ROWID| PERSON | 1 | 40 | 1 (0)| 00:00:01 | |* 3 | INDEX UNIQUE SCAN | PERSON_PK | 1 | | 0 (0)| 00:00:01 | |* 4 | INDEX RANGE SCAN | ORDERS_PK | 2 | 52 | 1 (0)| 00:00:01 | Predicate Information (identified by operation id) 3 - access("P"."P_ID"=1) 4 - access("O"."P_ID"=1) Note
    • dynamic sampling used for this statement `
  2. 但是,当数据变大(虽然只有几百个,300 ~ 400)并且视图查询变得复杂(使用“connect by”等)时,我认为计划发生了变化......
| 0 |选择声明 | | 1 | 29 | 2 (0)| 00:00:01 | | 1 |嵌套循环 | | 1 | 29 | 2 (0)| 00:00:01 | | 2 |按索引 ROWID 访问表| RP_TRANSACTION | 1 | 12 | 1 (0)| 00:00:01 | |* 3 |索引唯一扫描 | RP_TRANSACTION_PK | 1 | | 0 (0)| 00:00:01 | | 4 |按索引 ROWID 访问表| RP_REQUEST | 279 | 4743 | 1 (0)| 00:00:01 | |* 5 |索引唯一扫描 | RP_REQUEST_PK | 1 | | 0 (0)| 00:00:01 | 谓词信息(由操作 id 标识): -------------------------------------------------- - 3 - 访问(“TRANSACTION_ID”=18516648) 5 - 访问("REQ"."REQUEST_ID"="TRANS"."REQUEST_ID")

----下面是我的原帖

据我所知,oracle首先使用临时空间执行视图(逻辑视图),然后进行过滤。所以您的查询与

基本相同

选择 *
来自 ( 选择 *
来自 P 人,命令 O 其中 P.P_ID = O.P_ID ) 其中 P_ID='1234'

我认为你不能在逻辑视图上创建索引(物化视图使用索引)

另外,您应该知道,每次使用时都会执行 MY_VIEW 的查询 选择 * 来自 MY_VIEW 其中 P_ID = '1234'。

我的意思是每一次。当然,对于性能问题,这不是一个好主意

【讨论】:

  • 这与上面的第一个答案冲突:(
  • 有点...不完全相同的视图结构(P_ID 和所有内容)但在 oracle 10g 中有我自己的视图。
  • 我已经编辑了我的问题以提供显示使用索引的执行计划。您能否也提供您的执行计划?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-17
  • 1970-01-01
  • 2020-06-03
  • 2019-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多