【问题标题】:Oracle LEFT JOIN View performanceOracle LEFT JOIN 查看性能
【发布时间】:2014-05-23 01:35:50
【问题描述】:

我有两张桌子,它们不是大桌子。 我已经根据这个表创建了一个视图

select 
  tab_a.id as id, 
  tab_a.name as name 
from tableA as tab_a

UNION ALL

select 
  tab_b.id as id, 
  tab_b.name as name 
from tableB as tab_b

毕竟,我还有第三个表,我们称之为 tableMain 和字段:

tableMain.id、tableMain.status、tableMain.viewId

viewId存在加入view

最终选择的样子

SELECT tableMain.id
  FROM tableMain
  LEFT OUTER JOIN VIEW ON tableMain.viewId=view.id

在 VIEW 上加入 非常慢

如果我直接加入 tableA 或 tableB 会很快,但在使用视图时不会。

如果我在选择中使用 view.name 会更快

SELECT tableMain.id, VIEW.name
  FROM tableMain
  LEFT OUTER JOIN VIEW ON tableMain.viewId=view.id

如果我在选择中使用 VIEW 字段,不知道为什么 VIEW JOIN 工作得很快,

以及如何在没有它的情况下快速进行 VIEW JOIN。

发布计划:

好计划(在 SELECT 中使用 VIEW.name)

SELECT tableMain.id, VIEW.name
  FROM tableMain
  LEFT OUTER JOIN VIEW ON tableMain.viewId=view.id



| Id  | Operation            | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
|   0 | SELECT STATEMENT     |                |   220K|   440M|    50   (4)| 00:00:01 |
|*  1 |  HASH JOIN OUTER     |                |   220K|   440M|    50   (4)| 00:00:01 |
|   2 |   TABLE ACCESS FULL  | **tableMain**  | 19796 |  1527K|    42   (0)| 00:00:01 |
|   3 |   VIEW               | ***VIEW***     |  1115 |  2194K|     6   (0)| 00:00:01 |
|   4 |    UNION-ALL         |                |       |       |            |          |
|   5 |     TABLE ACCESS FULL| **tableA**     |   818 |  1609K|     3   (0)| 00:00:01 |
|*  6 |     TABLE ACCESS FULL| **tableB**     |   297 |  5346 |     3   (0)| 00:00:01 |

糟糕的计划(选择中没有 view.name)

SELECT tableMain.id
  FROM tableMain
  LEFT OUTER JOIN VIEW ON tableMain.viewId=view.id

| Id  | Operation                     | Name            | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
|   0 | SELECT STATEMENT              |                 |   220K|    19M|    51   (6)| 00:00:01 |        |      |            |
|   1 |  PX COORDINATOR               |                 |       |       |            |          |        |      |            |
|   2 |   PX SEND QC (RANDOM)         | :TQ10003        |   220K|    19M|    51   (6)| 00:00:01 |  Q1,03 | P->S | QC (RAND)  |
|*  3 |    HASH JOIN RIGHT OUTER      |                 |   220K|    19M|    51   (6)| 00:00:01 |  Q1,03 | PCWP |            |
|   4 |     PX RECEIVE                |                 |  1115 | 14495 |     6   (0)| 00:00:01 |  Q1,03 | PCWP |            |
|   5 |      PX SEND HASH             | :TQ10002        |  1115 | 14495 |     6   (0)| 00:00:01 |  Q1,02 | P->P | HASH       |
|   6 |       BUFFER SORT             |                 |   220K|    19M|            |          |  Q1,02 | PCWP |            |
|   7 |        VIEW                   | ***VIEW***      |  1115 | 14495 |     6   (0)| 00:00:01 |  Q1,02 | PCWP |            |
|   8 |         UNION-ALL             |                 |       |       |            |          |  Q1,02 | PCWP |            |
|   9 |          PX BLOCK ITERATOR    |                 |   818 | 10634 |     3   (0)| 00:00:01 |  Q1,02 | PCWC |            |
|  10 |           INDEX FAST FULL SCAN| ***tableA_PK*** |   818 | 10634 |     3   (0)| 00:00:01 |  Q1,02 | PCWP |            |
|  11 |          BUFFER SORT          |                 |       |       |            |          |  Q1,02 | PCWC |            |
|  12 |           PX RECEIVE          |                 |   297 |  2079 |     3   (0)| 00:00:01 |  Q1,02 | PCWP |            |
|  13 |            PX SEND ROUND-ROBIN| :TQ10000        |   297 |  2079 |     3   (0)| 00:00:01 |        | S->P | RND-ROBIN  |
|* 14 |             TABLE ACCESS FULL | **tableB**      |   297 |  2079 |     3   (0)| 00:00:01 |        |      |            |
|  15 |     BUFFER SORT               |                 |       |       |            |          |  Q1,03 | PCWC |            |
|  16 |      PX RECEIVE               |                 | 19796 |  1527K|    42   (0)| 00:00:01 |  Q1,03 | PCWP |            |
|  17 |       PX SEND HASH            | :TQ10001        | 19796 |  1527K|    42   (0)| 00:00:01 |        | S->P | HASH       |
|  18 |        TABLE ACCESS FULL      | **tableMain**   | 19796 |  1527K|    42   (0)| 00:00:01 |        |      |            |

为什么差别这么大?

【问题讨论】:

  • 这听起来像是一个有趣的优化器问题。但在花太多时间处理性能问题之前,至少要做两件事很重要:1) 收集所有相关对象的统计信息,2) 生成执行计划。对于统计数据,一个简单的exec dbms_stats.gather_table_stats(user, 'tableA'); ... 就足够了。对于执行计划,使用explain plan for select ...select * from table(dbms_xplan.display); 生成一个好的和坏的计划。然后在这里发布结果。
  • jonearles - 刚刚添加了两个计划

标签: performance oracle join


【解决方案1】:

有些东西在强制并行。视图有什么提示吗?此查询是否发生某种类型的计划管理?例如,是否有大纲、SQL 计划管理或仅针对错误查询的配置文件设置?您可以通过添加找到 解释计划的Note 部分。如果我是对的,那么只有一个执行计划中会有这样的内容:

Note
-----
   - SQL plan baseline "SQL_PLAN_01yu884fpund494ecae5c" used FOR this statement

还有助于定义“非常慢”。如果好查询在 0.01 秒内运行,而坏查询在 2 秒内运行,差异可能都是因为 并行性。但是,如果查询是针对具有更大数据的环境进行调整的,那么您可能仍然希望保留这个糟糕的计划 - 它可能在生产中运行得更好。

【讨论】:

  • 不,我认为这个查询没有任何提示或特殊之处,只是基于标准表的简单查询。是的,我尝试加入常规表(tableB)而不是视图,它运行 0.006,视图需要 2 到 2.5 秒。
  • 肯定有什么奇怪的事情发生了,除非被请求,否则并行性一般不会发生。你能发布坏计划的Note 部分吗?要修复糟糕的计划,在 11gR2 上,您可以添加类似 select /*+ no_parallel */ ... 的提示。尽管通常最好查明一个糟糕计划的根源,而不仅仅是暗示它。您可能需要查看this long list of reasons for parallelism
  • jonearles,很抱歉,我在生成的计划中没有看到注释。我使用 EXPLAIN PLAN FOR 并在 select * from table(dbms_xplan.display); 之后使用。 /*+ no_parallel */ 提示有帮助,但我也想知道是什么原因造成的。
  • 很奇怪。我想检查所有对象的DEGREE。还要查看select * from V$SQL where sql_id = '...'; 的好坏 SQL_ID 并寻找两者之间不同的“不寻常”。
  • 我所有的表的 DEGREE 都等于 1。如果我添加提示选择 /*+ 并行 */ - 结果与错误计划相同,我会看到一个注释部分 - 自动 DOP:由于缺少 IO 校准统计信息而跳过
猜你喜欢
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 2019-07-09
相关资源
最近更新 更多