【问题标题】:Force Oracle database not to materialize CTE强制 Oracle 数据库不实现 CTE
【发布时间】:2014-09-27 19:17:27
【问题描述】:

我对 cte 有一些问题,如果我使用这个查询,oracle 会物化 cte1 视图并且查询会很慢

with cte1 as (..),
    cte2 as ( ... use cte1 ...),
    cte3 as ( ... use cte1 ...)
select * from  cte2  join cte3
  on ...

在以下查询中,Oracle 没有实现 cte1,查询比以前快 20 倍:

with cte1 as (..),
    cte2 as ( ... use cte1 ...)
select * from cte2 on ....

还有

with cte1 as (..),
    cte3 as ( ... use cte1 ...)
select * from cte3 on ....

是否可以强制 Oracle 不实现 CTE,以便使用 idex?

查询1的执行计划:

Plan hash value: 1038428573

--------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                             |   126K|   104M|  1753   (1)| 00:00:22 |
|   1 |  TEMP TABLE TRANSFORMATION     |                             |       |       |            |          |
|   2 |   LOAD AS SELECT               | SYS_TEMP_0FD9DC639_11293183 |       |       |            |          |
|*  3 |    HASH JOIN                   |                             | 39285 |  1726K|  1618   (1)| 00:00:20 |
|*  4 |     HASH JOIN                  |                             | 31724 |   650K|   863   (1)| 00:00:11 |
|*  5 |      INDEX RANGE SCAN          | UQ1_xxxxxxx                 | 31724 |   402K|    23   (0)| 00:00:01 |
|   6 |      TABLE ACCESS FULL         | xxxx                        |   384K|  3005K|   837   (1)| 00:00:11 |
|   7 |     TABLE ACCESS FULL          | xxxxxxxxx                   |   481K|    11M|   753   (1)| 00:00:10 |
|*  8 |   HASH JOIN                    |                             |   126K|   104M|   136   (3)| 00:00:02 |
|*  9 |    HASH JOIN                   |                             |     3 |  1314 |    68   (2)| 00:00:01 |
|  10 |     TABLE ACCESS BY INDEX ROWID| xxxxxxxxxxxxxxxx            |     2 |    20 |     1   (0)| 00:00:01 |
|* 11 |      INDEX RANGE SCAN          | FK2_xxxxxxxxxxxxxxxx        |     2 |       |     1   (0)| 00:00:01 |
|* 12 |     VIEW                       |                             | 39285 |    16M|    66   (0)| 00:00:01 |
|  13 |      TABLE ACCESS FULL         | SYS_TEMP_0FD9DC639_11293183 | 39285 |  1035K|    66   (0)| 00:00:01 |
|* 14 |    VIEW                        |                             | 39285 |    16M|    66   (0)| 00:00:01 |
|  15 |     TABLE ACCESS FULL          | SYS_TEMP_0FD9DC639_11293183 | 39285 |  1035K|    66   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("ES"."xxxxxxxxxxxxx"="E"."xxxxxxxxxxxxxx")
   4 - access("CR"."xxxxxxxxxxxxxx"="E"."xxxxxxxxxxxxID")
   5 - access("CR"."xxxxxxxID"=TO_NUMBER(:xxxxxxxID))
   8 - access("EV"."xxxxxxxxxxxx_ID"="LA"."xxxxxx_ID")
   9 - access("LA"."xxxxxxxxxxxxx_ID"="EV2"."xxxxxxxxxxxx_ID")
  11 - access("LA"."xxxxxxxID"=359134)
  12 - filter("EV2"."xxxxxxxxxxxxxxxxID"=4)
  14 - filter("EV"."xxxxxxxxxxxxxxx_ID"=3 AND "EV"."xxxxxxxxxxxx_ID"=359134)

查询2的执行计划:

计划哈希值:1937334873

----------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                        |     1 |    55 |     4   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                   |                        |       |       |            |          |
|   2 |   NESTED LOOPS                  |                        |     1 |    55 |     4   (0)| 00:00:01 |
|   3 |    NESTED LOOPS                 |                        |     1 |    31 |     3   (0)| 00:00:01 |
|   4 |     NESTED LOOPS                |                        |     2 |    46 |     2   (0)| 00:00:01 |
|   5 |      TABLE ACCESS BY INDEX ROWID| xxxxxxxxxxxxxxxx       |     2 |    20 |     1   (0)| 00:00:01 |
|*  6 |       INDEX RANGE SCAN          | FK2_xxxxxxxxxxxxxxxx   |     2 |       |     1   (0)| 00:00:01 |
|*  7 |      TABLE ACCESS BY INDEX ROWID| xxxxxxxxxxxx           |     1 |    13 |     1   (0)| 00:00:01 |
|*  8 |       INDEX RANGE SCAN          | FK2_xxxxxxxxxxxx       |     4 |       |     1   (0)| 00:00:01 |
|*  9 |     TABLE ACCESS BY INDEX ROWID | xxxxxxxxxxxxx          |     1 |     8 |     1   (0)| 00:00:01 |
|* 10 |      INDEX UNIQUE SCAN          | PK_xxxxxxxxxxxxx       |     1 |       |     1   (0)| 00:00:01 |
|* 11 |    INDEX RANGE SCAN             | UQ1_xxxxxxxxxxxxxxxxxx |     1 |       |     1   (0)| 00:00:01 |
|  12 |   TABLE ACCESS BY INDEX ROWID   | xxxxxxxxxxxxxxxxxx     |     1 |    24 |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   6 - access("LA"."xxxxxx_ID"=359134)
   7 - filter("CR"."xxxxxxxID"=TO_NUMBER(:xxxxxxxID))
   8 - access("LA"."xxxxxxxxxxxxx_ID"="CR"."xxxxxxxxxxxx_ID")
   9 - filter("E"."xxxxxxxxxxxxxxx_ID"=4)
  10 - access("CR"."xxxxxxxxxxxxID"="E"."xxxxxxxxxxxxID")
  11 - access("ES"."xxxxxxxxxxxID"="E"."xxxxxxxxxxxxID")

【问题讨论】:

  • 你有一个真实的例子,以及表明你认为它做错了什么的执行计划吗?物化意味着它全部在内存中,这应该比使用索引访问基础表更快。
  • @AlexPoole 我添加了慢查询的执行计划。希望对您有所帮助。
  • cte1 在两个查询中是否相同?查询是否有任何 where 条件(cte2cte3 之间的连接除外)?
  • 是的 cte1 是相同的,并且外部选择中没有 where 子句。
  • 我认为 /*+ inline */ 提示应该做你想做的事,但这没有记录在 AFAICT 中,我自己从来没有使用过。可能值得一试。

标签: sql oracle view materialized-views


【解决方案1】:

有一个未记录的 /*+ inline */ 提示应该会阻止优化器实现 CTE。应该放在 CTE 本身中的 select 之后。

/*+ materialize */ 提示与此相反,即请求实现视图。

据我所知,这些都没有正式记录,因此请谨慎使用。在这种情况下,通过 Oracle 支持打开 SR 以获得一些建议是一个好主意,他们可以“批准”使用提示或提供替代方案(包括可以解决问题的潜在补丁/错误修复)。

【讨论】:

  • 为了让它像这个答案中描述的那样工作,......有没有在 Oracle 上激活的选项? ...是否有要安装的软件包?...有什么特别的事情要做吗?...因为我看不到它对我有用。感谢您的简短反馈或提示。
  • 不,不需要做任何事情。但正如我所说,这是不受支持且没有记录的,所以谁知道它在什么情况下会起作用或不会起作用。
  • 感谢您的回复。它似乎对我们的 12c 没有影响。
  • 据我所知,物化提示适用于 12c,但我没有内联的测试用例。
【解决方案2】:

+1 的问题和 Mat 的回答。

虽然 Oracle 进行 TEMP TABLE TRANSFORMATION 还有另一个原因。 如果您已将初始化参数 star_transformation_enabled 设置为 TRUE。

如果您不需要它,您可以通过运行将其关闭

更改会话集 star_transformation_enabled=TEMP_DISABLE;

这将使星形转换保持启用状态,但会关闭 TEMP TABLE TRANSFORMATION。

https://blogs.oracle.com/optimizer/entry/star_transformation

【讨论】:

    猜你喜欢
    • 2020-05-19
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    • 2019-01-16
    • 2015-05-08
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    相关资源
    最近更新 更多