oracle update并行,Oracle update 优化方式,tuning update!
在批量更新中,merge语句性能是最好的,因为merge可以多快读,而且可以启用并行,merge语句比一般update语句快,另外还有一种就是根据rowid来更新,这几种方法更新各有好处,首先使用merge更新,可以多快读,且速度是最快的,而且可以并行,速度就更快了,其次用rowid来更新,虽然是单块读,但如果加上组合索引的方式,那通过组合索引就不用回表,只扫描扫描就可以了,这也是比较快的,最后用普通的update,这种写法好处就是方便,容易写。下面来看一个简单的例子
1. 创建测试表,插入数据
PgSQL
SQL> create table test_a as select * from dba_objects;
Table created.
SQL> create table test_b as select * from dba_objects;
Table created.
SQL> insert into test_b select * from test_b;
91570 rows created.
SQL> /
183140 rows created.
SQL> /
366280 rows created.
SQL> /
732560 rows created.
SQL> commit;
Commit complete.
SQL> SELECT SUM(BYTES)/1024/1024 "SIZE(MB)" FROM DBA_SEGMENTS WHERE SEGMENT_NAME='TEST_B';
SIZE(MB)
----------
200
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
SQL>createtabletest_aasselect*fromdba_objects;
Tablecreated.
SQL>createtabletest_basselect*fromdba_objects;
Tablecreated.
SQL>insertintotest_bselect*fromtest_b;
91570rowscreated.
SQL>/
183140rowscreated.
SQL>/
366280rowscreated.
SQL>/
732560rowscreated.
SQL>commit;
Commitcomplete.
SQL>SELECTSUM(BYTES)/1024/1024"SIZE(MB)"FROMDBA_SEGMENTSWHERESEGMENT_NAME='TEST_B';
SIZE(MB)
----------
200
2. 在两个测试表上创建2个索引
PgSQL
SQL> create index idx_a on test_a(object_name,object_id);
Index created.
SQL> create index idx_b on test_b(object_id);
Index created.
1
2
3
4
5
6
7
SQL>createindexidx_aontest_a(object_name,object_id);
Indexcreated.
SQL>createindexidx_bontest_b(object_id);
Indexcreated.
3. 如果现在用最原始的update语句从test_a表更新test_b表,关联条件是object_id
PgSQL
SQL> update test_b b set b.object_name=(select a.object_name from test_a a where a.object_id=b.object_id);
1
SQL>updatetest_bbsetb.object_name=(selecta.object_namefromtest_aawherea.object_id=b.object_id);
我这里反正是过了很久都没有更新完成,毕竟测试库,没有那么大的buffer cache,这里的update相当于嵌套循环,test_b表有多少数据,那么子查询就要执行扫描多少次,对于一个几十万的表,扫描这么多次无疑是非常慢的。
4. 这里直接改成merge语句,设置多快读参数为128,开启并行
PgSQL
SQL> alter session set db_file_multiblock_read_count=128;
Session altered.
SQL> alter session enable parallel dml;
Session altered.
SQL> conn scott/tiger
Connected.
SQL> merge /*+ USE_HASH(C,H) FULL(C) */ into test_b c
2 using (select /*+INDEX(A) USE_HASH(A) */ a.object_name, a.object_id
3 from test_a a
4 where a.object_id in (select /*+ use_hash(b) index(b) */ object_id from test_b b)) h
5 on (c.object_id = h.object_id)
6 when matched then
7 update set c.object_name = h.object_name;
1465104 rows merged.
Elapsed: 00:00:12.03
SQL>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SQL>altersessionsetdb_file_multiblock_read_count=128;
Sessionaltered.
SQL>altersessionenableparalleldml;
Sessionaltered.
SQL>connscott/tiger
Connected.
SQL>merge/*+ USE_HASH(C,H) FULL(C) */intotest_bc
2using(select/*+INDEX(A) USE_HASH(A) */a.object_name,a.object_id
3fromtest_aa
4wherea.object_idin(select/*+ use_hash(b) index(b) */object_idfromtest_bb))h
5on(c.object_id=h.object_id)
6whenmatchedthen
7updatesetc.object_name=h.object_name;
1465104rowsmerged.
Elapsed:00:00:12.03
SQL>
可以看到使用merge语句更新了146W的数据,但是只花掉了10多秒的时间,而第一个update语句却迟迟没有更新成功。
简单看看这2中update方式的执行计划
PgSQL
SQL> explain plan for merge /*+ USE_HASH(C,H) FULL(C) */ into test_b c
using (select /*+INDEX(A) USE_HASH(A) */ a.object_name, a.object_id
from test_a a
2 3 4 where a.object_id in (select /*+ use_hash(b) index(b) */ object_id from test_b b)) h
5 on (c.object_id = h.object_id)
6 when matched then
7 update set c.object_name = h.object_name;
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------
Plan hash value: 1121481720
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | MERGE STATEMENT | | 91569 | 8137K| | 1684 (1)| 00:00:01 |
| 1 | MERGE | TEST_B | | | | | |
| 2 | VIEW | | | | | | |
|* 3 | HASH JOIN | | 91569 | 12M| 3760K| 1684 (1)| 00:00:01 |
| 4 | INDEX FULL SCAN | IDX_A | 91569 | 2682K| | 523 (1)| 00:00:01 |
| 5 | TABLE ACCESS FULL| TEST_B | 91570 | 10M| | 428 (1)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("C"."OBJECT_ID"="A"."OBJECT_ID")
17 rows selected.
SQL> explain plan for update test_b b set b.object_name=(select a.object_name from test_a a where a.object_id=b.object_id);
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------
Plan hash value: 703839442
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 91570 | 2682K| 47M (1)| 00:31:11 |
| 1 | UPDATE | TEST_B | | | | |
| 2 | TABLE ACCESS FULL| TEST_B | 91570 | 2682K| 428 (1)| 00:00:01 |
|* 3 | INDEX FULL SCAN | IDX_A | 1 | 30 | 523 (1)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("A"."OBJECT_ID"=:B1)
filter("A"."OBJECT_ID"=:B1)
16 rows selected.
使用merge into方式正确的使用的hash join连接,但普通的update语句,相当于嵌套循环,在id=3处看出来,当驱动表test_b返回一条数据的时候,被驱动表扫描一次,这里对于全表扫描会返回很多行的update来说,是非常不适合的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
SQL>explainplanformerge/*+ USE_HASH(C,H) FULL(C) */intotest_bc
using(select/*+INDEX(A) USE_HASH(A) */a.object_name,a.object_id
fromtest_aa
234wherea.object_idin(select/*+ use_hash(b) index(b) */object_idfromtest_bb))h
5on(c.object_id=h.object_id)
6whenmatchedthen
7updatesetc.object_name=h.object_name;
Explained.
SQL>select*fromtable(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------
Planhashvalue:1121481720
---------------------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|TempSpc|Cost(%CPU)|Time|
---------------------------------------------------------------------------------------
|0|MERGESTATEMENT||91569|8137K||1684(1)|00:00:01|
|1|MERGE|TEST_B||||||
|2|VIEW|||||||
|*3|HASHJOIN||91569|12M|3760K|1684(1)|00:00:01|
|4|INDEXFULLSCAN|IDX_A|91569|2682K||523(1)|00:00:01|
|5|TABLEACCESSFULL|TEST_B|91570|10M||428(1)|00:00:01|
---------------------------------------------------------------------------------------
PredicateInformation(identifiedbyoperationid):
---------------------------------------------------
3-access("C"."OBJECT_ID"="A"."OBJECT_ID")
17rowsselected.
SQL>explainplanforupdatetest_bbsetb.object_name=(selecta.object_namefromtest_aawherea.object_id=b.object_id);
Explained.
SQL>select*fromtable(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------
Planhashvalue:703839442
-----------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
-----------------------------------------------------------------------------
|0|UPDATESTATEMENT||91570|2682K|47M(1)|00:31:11|
|1|UPDATE|TEST_B|||||
|2|TABLEACCESSFULL|TEST_B|91570|2682K|428(1)|00:00:01|
|*3|INDEXFULLSCAN|IDX_A|1|30|523(1)|00:00:01|
-----------------------------------------------------------------------------
PredicateInformation(identifiedbyoperationid):
---------------------------------------------------
3-access("A"."OBJECT_ID"=:B1)
filter("A"."OBJECT_ID"=:B1)
16rowsselected.
使用mergeinto方式正确的使用的hashjoin连接,但普通的update语句,相当于嵌套循环,在id=3处看出来,当驱动表test_b返回一条数据的时候,被驱动表扫描一次,这里对于全表扫描会返回很多行的update来说,是非常不适合的。
PgSQL
SQL> DECLARE
2 CURSOR CUR_B IS
3 SELECT a.object_id, a.object_name, b.ROWID ROW_ID
4 FROM test_a A, test_b B
5 WHERE A.object_id = B.object_id
6 ORDER BY B.ROWID;
7 V_COUNTER NUMBER;
8 BEGIN
9 V_COUNTER := 0;
10 FOR ROW_B IN CUR_B LOOP
11 UPDATE test_b b SET object_name = ROW_B.object_name WHERE ROWID = ROW_B.ROW_ID;
12 V_COUNTER := V_COUNTER + 1;
13 IF (V_COUNTER >= 10000) THEN
14 COMMIT;
15 dbms_output.put_line('Updated: ' ||V_COUNTER || ' lines.');
16 V_COUNTER := 0;
17 END IF;
18 END LOOP;
19 COMMIT;
20 END;
21 /
PL/SQL procedure successfully completed.
Elapsed: 00:01:09.35
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SQL>DECLARE
2CURSORCUR_BIS
3SELECTa.object_id,a.object_name,b.ROWIDROW_ID
4FROMtest_aA,test_bB
5WHEREA.object_id=B.object_id
6ORDERBYB.ROWID;
7V_COUNTERNUMBER;
8BEGIN
9V_COUNTER:=0;
10FORROW_BINCUR_BLOOP
11UPDATEtest_bbSETobject_name=ROW_B.object_nameWHEREROWID=ROW_B.ROW_ID;
12V_COUNTER:=V_COUNTER+1;
13IF(V_COUNTER>=10000)THEN
14COMMIT;
15dbms_output.put_line('Updated: '||V_COUNTER||' lines.');
16V_COUNTER:=0;
17END IF;
18END LOOP;
19COMMIT;
20END;
21/
PL/SQLproceduresuccessfullycompleted.
Elapsed:00:01:09.35
这里通过rowid来更新,前文已经说过,rowid是单块读的,没有merge快,而实验也正好证明了这个问题,merge语句要比通过rowid来更新要快很多,不过在通过rowid更新的时候要注意,我这里用了order by rowid,是在buffer cache不够大的情况下使用,性能比较好,保证被更新的表不被page out,当然如果buffer cache够大,就不会存在这种情况了,反而比不加order by rowid要快,因为少了排序,而且buffer cache也能容纳下这2个表。用rowid的好处就是可以批量提交,但不足的地方就是没有merge快,不能并行更新。
转载请注明: 版权所有,文章允许转载,但必须以链接方式注明源地址,否则追究法律责任!
最后编辑:2014-03-05作者:Jerry
一个积极向上的小青年,热衷于分享--Focus on DB,BI,ETL
oracle update并行,Oracle update 优化方式,tuning update!相关推荐
- oracle查询挂起,表挂起更新查询Oracle 11g(Table hangs on Update query Oracle 11g)
表挂起更新查询Oracle 11g(Table hangs on Update query Oracle 11g) 我正在更新一个Oracle表字段,引用另一个具有类似Key字段的表,但在此特定表上, ...
- Oracle数据库之oracle update set select from 关联更新
本文主要向大家介绍了Oracle数据库之oracle update set select from 关联更新,通过具体的内容向大家展现,希望对大家学习Oracle数据库有所帮助. 工作中有个需求,现在 ...
- oracle有的表带$,Oracle Update
在表的更新操作中,在很多情况下需要在表达式中引用要更新的表以外的数据.象sql server提供了update的from 子句,可以将要更新的表与其它的数据源连接起来.虽然只能对一个表进行更新,但是通 ...
- Oracle 10.2.0.5.4 Patch Set Update (PSU) – Patch No: p12419392
有关Oracle patch和PSU,PSR 说明参考我的blog: Oracle 补丁体系 及opatch 工具 介绍 http://blog.csdn.net/tianlesoftware/art ...
- oracle instead of update触发器,Oracle中的instead of触发器
Instead of : 用Trigger的内容替换 事件本身的动作,该触发器用在视图上,举例: 一:创建一个update替代触发器 (1)创建一个视图 1 create or replace vie ...
- Oracle数据库优化器的优化方式
Oracle是世界领先的信息管理软件开发商,因其复杂的关系数据库产品而闻名.本文介绍Oracle优化器,它是一个非常好用的工具.Oracle在执行一个SQL之前,首先要分析一下语句的执行计划,然后再按 ...
- oracle 两种优化器,Oracle的优化器有两种优化方式(一)
Oracle的优化器有两种优化方式(整理), 2010-04-13 RBO方式:基于规则的优化方式(Rule-Based Optimization,简称为RBO) 优化器在分析SQL语句时,所遵循的 ...
- Oracle 错误代码详解及解决方式--ORA
ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常. ORA-00017: 请求会话以设置跟踪事件 ORA-00018: 超出最大会话数 OR ...
- Oracle Hints,Oracle并行模式(Parallel) /*+parallel(t,4)*/ 在SQL调优中的重要作用
/*+parallel(t,4)*/在SQL调优中的重要作用! 2013年11月17日 12:59:24 雾里看花5566 阅读数:5422更多 个人分类: 数据库-oracle 谈谈HINT /*+ ...
最新文章
- 一篇SSM框架整合友好的文章(二)
- 问答:双总线并机,可以使用不同品牌的ups吗?
- Running /usr/bin/wineserver -w. This will hang until all wine processes XXXX terminate
- linux下安装TensorFlow(centos)
- Bootstrap 折叠插件
- 有了数据湖,距离数据仓库消失还有几年?
- 气球java游戏,游戏 | 最适合春季玩气球的这12种玩法你玩过吗?
- 【总结】仰望星空,脚踏实地 2017.09-2018.02
- 编写python程序实现分段函数_python分段函数如何编写?_后端开发
- 【linux】循序渐进学运维-基础篇-文件的软硬链接
- 八、在创业公司工作的心理历程
- SAP小磁带备份注意事项
- 计算机word综合操作,『word2010表格操作及综合排版计算机实验报告』excle2010实验操作...
- 计算机视觉有哪些SCI期刊? - 易智编译EaseEditing
- 编写一个程序,模拟扔硬币的结果.
- smurf攻击的工作原理
- AutoCAD/Civil 3D 学习笔记
- 淘宝店铺商品全量爬取
- CocosCreator | 微信小游戏排行榜 微信开放域
- 基于STM32F103的USB学习笔记27 - CustomHID
热门文章
- C# 线程手册 第二章 .NET 中的线程 线程的优势
- Python之数据分析(算数平均值、加权平均值、最大值与最小值)
- fashionmnist数据集_Keras实现Fashion MNIST数据集分类
- docker宿主机访问容器_干货来啦!带你初探Docker逃逸
- cmd 220 ftp 远程主机关闭连接_下载ftp软件,下载ftp软件需要注意3点
- Python花式编程:多层嵌套列表扁平化
- 力扣429. N 叉树的层序遍历(JavaScript)
- openresty nginx php,diy 你的nginx-OpenResty
- 推箱子如何实现悔步_推箱子时代又来临,表里世界会发生什么?
- html段落自动删除,利用JS代码自动删除稿件的普通弹幕功能