1. 多列关联更新改写示例
1. 模拟数据
create table t_objects as select * from dba_objects;
create table t_tables as select * from dba_tables;
alter table t_objects add tablespace_name varchar2(30);
alter table t_objects add flag varchar2(2);
2. 现在需要把t_tables.object_id>10000的t_tables.tablespace_name与t_tables.'2'的值
更新到t_objects.tablespace_name 与t_objects.flag。
错误的写法:
update t_objects a
set (a.tablespace_name, a.flag) =
(select b.tablespace_name, '2'
from t_tables b
where a.owner = b.owner
and a.object_name = b.table_name)
where a.object_id> 10000
因为如果where子句不加
(exists (select b.tablespace_name from t_tables b
where a.owner = b.owner and a.object_name = b.table_name))
的话,会多处理一些没有关联上的数据,而这些没关联上的数据,是用null值更新的。
正确的写法:
update t_objects a
set (a.tablespace_name, a.flag) =
(select b.tablespace_name, '2'
from t_tables b
where a.owner = b.owner
and a.object_name = b.table_name)
where exists (select b.tablespace_name
from t_tables b
where a.owner = b.owner
and a.object_name = b.table_name)
and a.object_id> 10000
Elapsed: 00:00:00.67
Execution Plan
Plan hash value: 2130220419
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | UPDATE STATEMENT | | 23341 | 3419K| 1027K (5)| 03:25:26 |
| 1 | UPDATE | T_OBJECTS | | | | |
|* 2 | HASH JOIN RIGHT SEMI| | 23341 | 3419K| 93 (3)| 00:00:02 |
| 3 | VIEW | VW_SQ_1 | 3062 | 101K| 21 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | T_TABLES | 3062 | 101K| 21 (0)| 00:00:01 |
|* 5 | TABLE ACCESS FULL | T_OBJECTS | 23346 | 2644K| 71 (2)| 00:00:01 |
|* 6 | TABLE ACCESS FULL | T_TABLES | 1 | 51 | 21 (0)| 00:00:01 |
Predicate Information (identified by operation id):
2 - access("A"."OWNER"="ITEM_1" AND "A"."OBJECT_NAME"="ITEM_2")
5 - filter("A"."OBJECT_ID">10000)
6 - filter("B"."OWNER"=:B1 AND "B"."TABLE_NAME"=:B2)
Note
- dynamic sampling used for this statement (level=2)
Statistics
0 recursive calls
2614 db block gets
255891 consistent gets
507 physical reads
643016 redo size
839 bytes sent via SQL*Net to client
1115 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
2555 rows processed
3. 利用merge改写后
merge into t_objects a
using t_tables b
on (a.owner = b.owner and a.object_name = b.table_name)
when matched then
update set a.tablespace_name = b.tablespace_name, a.flag = '2'
where a.object_id> 10000
Elapsed: 00:00:00.06
Execution Plan
Plan hash value: 1970127410
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
| 0 | MERGE STATEMENT | | 3062 | 768K| | 567 (1)| 00:00:07 |
| 1 | MERGE | T_OBJECTS | | | | | |
| 2 | VIEW | | | | | | |
|* 3 | HASH JOIN | | 3062 | 2332K| 1656K| 567 (1)| 00:00:07 |
| 4 | TABLE ACCESS FULL| T_TABLES | 3062 | 1617K| | 21 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL| T_OBJECTS | 33077 | 7720K| | 71 (2)| 00:00:01 |
Predicate Information (identified by operation id):
3 - access("A"."OWNER"="B"."OWNER" AND "A"."OBJECT_NAME"="B"."TABLE_NAME")
Note
- dynamic sampling used for this statement (level=2)
Statistics
0 recursive calls
2605 db block gets
511 consistent gets
0 physical reads
607260 redo size
840 bytes sent via SQL*Net to client
955 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
2555 rows processed
4. 优化后的物理读与逻辑读,都比之前减少很多,执行时间也少了许多。
2. 用Merge改写有聚合操作的Update
1. 模拟数据
create table t_objects as select * from dba_objects;
create table t_tables as select * from dba_tables;
insert into t_tables select * from t_tables;
insert into t_tables select * from t_tables;
insert into t_tables select * from t_tables;
commit;
alter table t_objects add tablespace_name varchar2(30);
alter table t_objects add flag varchar2(2);
2. 更新数据到t_objects表中
update t_objects a
set (a.tablespace_name, a.flag) =
(select distinct b.tablespace_name, '2'
from t_tables b
where a.owner = b.owner
and a.object_name = b.table_name)
where exists (select distinct b.tablespace_name
from t_tables b
where a.owner = b.owner
and a.object_name = b.table_name)
and a.object_id> 10000
Elapsed: 00:00:04.84
Execution Plan
Plan hash value: 1460256570
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | UPDATE STATEMENT | | 23346 | 3419K| 7190K (2)| 23:58:10 |
| 1 | UPDATE | T_OBJECTS | | | | |
|* 2 | HASH JOIN RIGHT SEMI| | 23346 | 3419K| 225 (2)| 00:00:03 |
| 3 | VIEW | VW_SQ_1 | 26203 | 870K| 153 (1)| 00:00:02 |
| 4 | TABLE ACCESS FULL | T_TABLES | 26203 | 870K| 153 (1)| 00:00:02 |
|* 5 | TABLE ACCESS FULL | T_OBJECTS | 23346 | 2644K| 71 (2)| 00:00:01 |
| 6 | HASH UNIQUE | | 3 | 153 | 154 (2)| 00:00:02 |
|* 7 | TABLE ACCESS FULL | T_TABLES | 3 | 153 | 153 (1)| 00:00:02 |
Predicate Information (identified by operation id):
2 - access("A"."OWNER"="ITEM_1" AND "A"."OBJECT_NAME"="ITEM_2")
5 - filter("A"."OBJECT_ID">10000)
7 - filter("B"."OWNER"=:B1 AND "B"."TABLE_NAME"=:B2)
Note
- dynamic sampling used for this statement (level=2)
Statistics
28 recursive calls
5202 db block gets
1972653 consistent gets
0 physical reads
1119588 redo size
824 bytes sent via SQL*Net to client
1144 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
3 sorts (memory)
0 sorts (disk)
2555 rows processed
3. merge改写
merge into (select owner, object_name, tablespace_name, flag
from t_objects
where object_id > 10000) a
using (select owner, table_name, tablespace_name
from t_tables
group by owner, table_name, tablespace_name) b
on (a.owner = b.owner and a.object_name = b.table_name)
when matched then
update set a.tablespace_name = b.tablespace_name, a.flag = '2'
Elapsed: 00:00:00.07
Execution Plan
Plan hash value: 1597301946
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
| 0 | MERGE STATEMENT | | 23346 | 1139K| | 460 (2)| 00:00:06 |
| 1 | MERGE | T_OBJECTS | | | | | |
| 2 | VIEW | | | | | | |
| 3 | SORT GROUP BY | | 23346 | 4080K| | 460 (2)| 00:00:06 |
|* 4 | HASH JOIN | | 23346 | 4080K| 1616K| 458 (1)| 00:00:06 |
| 5 | TABLE ACCESS FULL| T_TABLES | 26203 | 1305K| | 153 (1)| 00:00:02 |
|* 6 | TABLE ACCESS FULL| T_OBJECTS | 23346 | 2918K| | 71 (2)| 00:00:01 |
Predicate Information (identified by operation id):
4 - access("OWNER"="OWNER" AND "OBJECT_NAME"="TABLE_NAME")
6 - filter("OBJECT_ID">10000)
Note
- dynamic sampling used for this statement (level=2)
Statistics
9 recursive calls
2623 db block gets
1274 consistent gets
0 physical reads
643324 redo size
840 bytes sent via SQL*Net to client
1161 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
2555 rows processed
4. merge 改写后,性能大大提升