执行计划与预期不符

时间:2016-12-07 13:08:45

标签: sql oracle performance sql-execution-plan

我遇到了一些我无法解释的怪异事。

我正在使用以下查询:

MERGE INTO Main_Table t
USING  Stg_Table s 
 ON(s.site_id = t.site_id)
 WHEN MATCHED THEN
   UPDATE SET t.arpu_prev_period = s.arpu_prev_period 
              .... --50 more columns  
  where  t.period_code = 201612

Stg_Table:已编入索引(Site_Id)

MAIN_TABLE:
- 索引(Period_code,Site_id)
- 由period_code分区
- 注意 - 我尝试仅在Site_Id上添加一个索引,相同的执行计划。

我希望执行计划使用单分区扫描,但我得到的是Partition list all

这是执行计划:

6   |   0 | MERGE STATEMENT       |                               |
7   |   1 |  MERGE                | Main_Table                    |
8   |   2 |   VIEW                |                               |
9   |   3 |    HASH JOIN          |                               |
10  |   4 |     TABLE ACCESS FULL | Stg_Table                     |
11  |   5 |     PARTITION LIST ALL|                               |
12  |   6 |      TABLE ACCESS FULL| Main_Table                    |

编辑:为了澄清,如果不清楚,我不是在寻找如何让Oracle只扫描一个分区的答案,我已经知道放置{{在t.period_code = 201612子句中1}}没问题。我的问题是 - 为什么oracle不评估应该只过滤特定分区的ON子句?

3 个答案:

答案 0 :(得分:3)

似乎根本没有对UPDATE的WHERE子句进行优化。

create table t (n,x) as select level n,-1 x from dual connect by level <= 1000000;
create table s (n,x) as select level n,-1 x from dual connect by level <= 1000000;
merge into t
using s
on (s.n = t.n)
when matched then update set t.x = s.x where 1=2
;

enter image description here

答案 1 :(得分:1)

请考虑将t.period_code = 201612移至条件:on (t.period_code = 201612 and s.site_id = t.site_id)。我认为您的查询正在尝试访问所有分区PARTITION LIST ALL,这就是问题所在。

如果添加访问单个分区的条件,它应该会更好。

另一种选择是:

MERGE INTO (select * from Main_Table where period_code = 201612) t
USING  Stg_Table s 
 ON(t.period_code = 201612 and s.site_id = t.site_id)
 WHEN MATCHED THEN
   UPDATE SET t.arpu_prev_period = s.arpu_prev_period 
              .... --50 more columns  
  where  t.period_code = 201612

直接指出该更新仅适用于一个分区。

修改

好的,所以试着回答问题原因。 Oracle无法将两个条件合并为一个。 where包含有关分区的信息,但要对已加入的数据应用where,首先应用ON条件。但是在那个时间点它没有关于分区的信息site_id所以它决定扫描所有分区。您需要在第一步(即加入on)通知Oracle您想要使用的分区。

换句话说,首先需要解析包含有关分区信息的where

MERGE INTO Main_Table t
USING  Stg_Table s 
 ON(s.site_id = t.site_id)

在这里你必须访问所有分区。 wherewhen matched的一部分,因此首先我们需要确定是否存在任何匹配,而不了解分区。

答案 2 :(得分:1)

应该区分WHERE clause合并插入/更新子句和WHERE clause SELECT语句。

MERGE子句通常是saing - 不要更新不要插入。一般情况下,一代ACCESS谓词并非无足轻重。

正如其他人在仅有一个UPDATE WHERE子句的最简单情况中指出的那样,从11g开始没有执行ACCESS谓词生成。

这也是文件

merge_update_clause

  

如果希望数据库仅在指定的条件为真时才执行更新操作,请指定where_clause。条件可以指数据源或目标表。如果条件不为真,则数据库会在将行合并到表中时跳过更新操作。

即。谓词跳过更新而不是行源中的记录。