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」の部分はほとんどの行を拒否しますが、mergeは最初に「using」内にあるすべての行をクエリしますか?その場合、行の95%がt1.column2 = somevalue AND t1.column3 = someothervalueと一致しないため、その部分はほとんどの場合無駄に実行されます。それとも、Oracleはそれを行わないほど賢いのでしょうか。

4

1 に答える 1

1

はい、Oracleはテーブル1をusingビュークエリに結合するようにクエリを書き直します。したがって、t1.column2 = somevalue AND t1.column3 = someothervalueが選択的であり、Oracleがこれを認識している場合は、クエリがTABLE1から駆動され、usingビューのテーブルに結合されることを計画で確認する必要があります。説明プランを実行して確認してください。すなわち

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)

あなたはそれが表1に適用されたインデックスを見ることができます

INDEX RANGE SCAN          | TABLE1_IDX

したがって、table1でスキャンされた多くの行を削除します(私のテーブルを考慮するとハッシュ結合の方が適切でしたが、あなたの場合、結合ステップでネストされたループアプローチが表示される場合があります)。

于 2012-12-11T13:01:36.290 に答える