1
MERGE INTO table1 t1
USING 
    (SELECT column1 
     FROM table2 join table3 on... 
     WHERE table2.column5 = 'xyz') t2
ON (t1.column1 = t2.column1 AND t1.column2 =  somevalue 
AND t1.column3 = someothervalue)
WHEN not matched 
THEN 
INSERT ...

“on”部分将拒绝大多数行,但合并是否首先查询“using”内的所有行?在这种情况下,该部分大部分时间将无用运行,因为 95% 的行将不匹配t1.column2 = somevalue AND t1.column3 = someothervalue。还是甲骨文足够聪明,不会那样做?

4

1 回答 1

1

是的,Oracle 将重写查询以将 table1 连接到使用视图查询。因此,如果t1.column2 = somevalue AND t1.column3 = someothervalue是选择性的并且 Oracle 意识到了这一点,您应该在计划中看到查询将从 TABLE1 驱动,然后连接到使用视图中的表中。只需运行一个解释计划来检查它。IE

set linesize 200 pagesize 200
explain plan for
merge....;
select * from table(dbms_xplan.display());

您应该会看到 Oracle 已经为您完成了这项工作。

例如:

SQL> create table table1(id number primary key, t2_id number, str varchar2(20), notes varchar2(20));

Table created.

SQL> create table table2(id number primary key, notes varchar2(20));

Table created.

SQL>
SQL> insert into table1
  2  select rownum, rownum, case mod(rownum, 100) when 0 then 'ONE' else 'TWO' end, null
  3  from dual connect by level <=1000000;

1000000 rows created.

SQL>
SQL> insert into table2
  2  select rownum, dbms_random.string('x', 10)
  3  from dual connect by level <=1000000;

1000000 rows created.

SQL>
SQL> create index table1_idx on table1(str);

Index created.

SQL> exec dbms_stats.gather_table_stats(user, 'TABLE1', method_opt=>'for all indexed columns size skewonly');

PL/SQL procedure successfully completed.

SQL> exec dbms_stats.gather_table_stats(user, 'TABLE2');

PL/SQL procedure successfully completed.

所以生病添加t1.str = 'ONE'时非常有选择性:

SQL> explain plan for
  2  merge into table1 t1
  3  using (select * from table2 t where t.id > 1000) t2
  4  on (t2.id = t1.t2_id and t1.str = 'ONE')
  5  when matched then update
  6  set t1.notes = t2.notes;

Explained.

SQL> @explain ""

Plan hash value: 2050534005

---------------------------------------------------------------------------------------------
| Id  | Operation                      | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | MERGE STATEMENT                |            |   441 | 11025 |   929   (5)| 00:00:12 |
|   1 |  MERGE                         | TABLE1     |       |       |            |          |
|   2 |   VIEW                         |            |       |       |            |          |
|*  3 |    HASH JOIN                   |            |   441 | 12348 |   929   (5)| 00:00:12 |
|*  4 |     TABLE ACCESS BY INDEX ROWID| TABLE1     |   441 |  5733 |    69   (2)| 00:00:01 |
|*  5 |      INDEX RANGE SCAN          | TABLE1_IDX |  8828 |       |    21   (0)| 00:00:01 |
|*  6 |     TABLE ACCESS FULL          | TABLE2     |   994K|    14M|   848   (4)| 00:00:11 |
-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("T"."ID"="T1"."T2_ID")
   4 - filter("T1"."T2_ID">1000)
   5 - access("T1"."STR"='ONE')
   6 - filter("T"."ID">1000)

您可以看到它在 table1 上应用了索引

INDEX RANGE SCAN          | TABLE1_IDX

因此删除了在 table1 上扫描的大量行(考虑到我的表,哈希连接更合适,但在您的情况下,您可能会在连接步骤中看到嵌套循环方法)。

于 2012-12-11T13:01:36.290 回答