Oracle并行操作——并行DML操作

前端之家收集整理的这篇文章主要介绍了Oracle并行操作——并行DML操作前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

对大部分的OLTP系统而言,并行DML(PDML)的应用场景不多。大多数的PDML操作集中在下面几个场景下:

ü系统移植,从旧系统中导入原始数据和基础数据;

ü数据仓库系统Data Warehouse定期进行大批量原始数据导入和清洗;

ü借助一些专门的工具,如sql loader,进行数据海量导入;

本篇主要介绍并行DML操作的一些细节和注意方面。

1、环境准备

Oracle并行操作前提两个条件,其一是盈余的软硬件资源,其二是海量的大数据量操作。

//操作系统和DB环境

sql> select * from v$version where rownum<2;

BANNER

--------------------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

sql> show parameter cpu_count;

NAMETYPEVALUE

------------------------------------ ---------------------- ------------------------------

cpu_countinteger4

sql>

//数据环境

sql> select count(*) from t;

COUNT(*)

----------

10039808

Executed in 4.072 seconds

2、并行统计量收集

为了实现CBO的正常工作,我们通常要保证Oracle数据字典中保留有关于数据表完全的统计信息描述。统计信息包括数据行数、取值分布、离散程度等等指标。收集统计量是一项比较重要的工作。当数据表很大的时候,即使使用了比例抽样的方法,进行汇总统计的数据量也是很大。所以这种场合下,是可以应用到并行技术的。

在目前的Oracle版本中,通常是使用dbms_stats包进行统计量收集。相对于过去的analyze table xxx命令,dbms_stats包对于统计量收集更加完全,应对分区状况更好。在dbms_stats方法中,存在参数degree,表示并行度,可以直接指定希望的收集并行度。

--收集统计量,指定并行度

sql> exec dbms_stats.gather_table_stats(user,'T',cascade => true,degree => 7);

PL/sql procedure successfully completed

Executed in15.32seconds

系统使用15.32s的时间完成了收集。

在收集过程中,我们观察v$px_session和v$px_process两个视图的状态。检查并行伺服进程池的状况。

sql> select * from v$px_process;

SERVER_NAME STATUSPID SPIDSIDSERIAL#

----------- --------- ---------- ------------------------ ---------- ----------

P006IN USE100 190709823550729

P001IN USE65 1310745217835585

P002IN USE73 963388818425268

P003IN USE85 2247898622333339

P000IN USE63 1874331450016029

P004IN USE95 1422138050926446

P005IN USE99 2306870851020895

7 rows selected

系统依据并行度要求,分配了7个进程进行操作。

//并行会话信息

sql> select * from v$px_session;

SADDRSIDSERIAL#QCSIDQCSERIAL#DEGREE REQ_DEGREE

---------------- ---------- ---------- ---------- -------------------- ----------

070000007D2BA680500160293242615277

070000007FE7EC70178355853242615277

070000007FE6D5D0184252683242615277

070000007FDFC2C0223333393242615277

070000007D2A0490509264463242615277

070000007D29D620510208953242615277

070000007FC9448035507293242615277

070000007D12FB0032426152324

(篇幅原因,有截取结果……)

8 rows selected

注意,在请求了并行度degree=7的情况下,Oracle根据cpu数量分配了7个并行slave进程进行操作。会话层面,七个slave进程分别对应七个会话信息进行并行操作。同时,存在一个额外会话(sid=324),充当全局协调者coordinator的角色。v$px_session中的qcsid字段含义为“Session serial number of the parallel coordinator”,就是并行操作中扮演协调者角色的进程。

如果不使用并行收集,只是简单的串行收集,我们查看一下效率情况。

//指定串行

degree => 1);

Executed in46.816seconds

效果清晰可见,从原来的15s多的收集时间,放大为47s左右,几乎是三倍的损耗。

结论:对于统计量收集而言,如果作业时间可以避开业务高峰时间窗口,进行并行操作收集统计量还是一个不错的选择。

3、并行insert操作

下面进行并行insert操作,我们选择使用hint来进行并行控制。

//开启PDML的开关

sql> alter session enable parallel dml;

Session altered

Executed in 0.016 seconds

使用hint,开启8个并行度进行insert操作。

--并行insert

sql>insert /*+ parallel(t,8) */ into t select * from t;

10039808 rows inserted

Executed in 76.238 seconds

运行过程中,出现的并行操作过程如下。

//开启8个并行度;

SADDRSIDSERIAL#QCSIDQCSERIAL#

---------------- ---------- ---------- ---------- ----------

070000007FFF52E0361312332426152

070000007FE849501765002832426152

070000007FE7EC701783550832426152

070000007FE0AAF0218599432426152

070000007D29D6205102082932426152

070000007D2A04905092639132426152

070000007FC94480355061532426152

070000007FFFAFC03593251632426152

070000007D12FB0032426152324

9 rows selected

SERVER_NAME STATUSPID SPIDSID SERIAL#

P006IN USE100 190055903550615

P001IN USE69 1939871017650028

P002IN USE73 963396817835508

P003IN USE85 230686942185994

P007IN USE102 1874329835932516

P000IN USE66 142213523613123

P005IN USE99 2123388450926391

P004IN USE95 1907118851020829

此时,我们尝试抽取出执行计划。

//从shared_pool中尝试获取到指定的记录;

sql> select sql_text,sql_id,version_count from v$sqlarea where sql_text like 'insert /*+ parallel(t,8) */%';

sql_TEXTsql_IDVERSION_COUNT

-------------------------------------------------- ------------- -------------

insert /*+ parallel(t,8) */ into t select * from t67wymm0jhw3gv2

Executed in 0.234 seconds

利用sql_id,尝试抽取出shared_pool中的执行计划。

//抽取出执行计划,篇幅原因,有删节……

sql> select * from table(dbms_xplan.display_cursor('67wymm0jhw3gv',format => 'advanced',cursor_child_no => 1));

PLAN_TABLE_OUTPUT

----------------------------------------------------------------------------------------------------

sql_ID67wymm0jhw3gv,child number 1

-------------------------------------

Plan hash value: 4064487821

| Id| Operation| Name| Rows| Bytes | Cost (%cpu)| Time|TQ|IN-OUT| PQ Distrib |

|0 | INSERT STATEMENT||||2718 (100)|||||

|1 |PX COORDINATOR|||||||||

|2 |PX SEND QC (RANDOM) | :TQ10000 |5019K|469M|2718(1)| 00:00:33 |Q1,00 | P->S | Q

|3 |LOAD AS SELECT||||||Q1,00 | PCWP ||

|4 |PX BLOCK ITERATOR ||5019K|469M|2718(1)| 00:00:33 |Q1,00 | PCWC ||

|*5 |TABLE ACCESS FULL| T|5019K|469M|2718(1)| 00:00:33 |Q1,102);background:#C0C0C0;">Predicate Information (identified by operation id):

---------------------------------------------------

5 - access(:Z>=:Z AND :Z<=:Z)

Note

-----

-automatic DOP: Computed Degree of Parallelism is 8 because of degree limit

已选择66行。

已用时间:00: 00: 00.40

如果不使用并行操作,进行如此规模的insert操作,会如何呢?

//使用noparallel的hint进行并行抑制;

sql>insert /*+ noparallel */ into t select * from t;

Executed in 87.813 seconds

对应的执行计划如下:

sqlarea where sql_text like 'insert /*+ noparallel */%';

sql_TEXTsql_ID VERSION_COUNT

insert /*+ noparallel */ into t select * from t9u0xcrr3bcjs11

sql> select * from table(dbms_xplan.display_cursor('9u0xcrr3bcjs1',cursor_child_no => 0));

sql_ID9u0xcrr3bcjs1,child number 0

insert /*+ noparallel */ into t select * from t

Plan hash value: 2153619298

---------------------------------------------------------------------------------

| Id| Operation| Name | Rows| Bytes | Cost (%cpu)| Time|

|0 | INSERT STATEMENT|||| 19601 (100)||

|1 |LOAD TABLE CONVENTIONAL ||||||

|2 |TABLE ACCESS FULL| T|5019K|469M| 19601(1)| 00:03:56 |

4、结论

本篇对PDML进行了简单的介绍,包括使用方法和并行度设置。由于篇幅原因,只介绍了并行insert和并行统计量的收集。并行update和delete本质相同,就不加以累述了。

最后,并行操作是一种带有特殊性的操作,绝对不要将其轻易作为经常性无监管下的操作

原文链接:https://www.f2er.com/oracle/206027.html

猜你在找的Oracle相关文章