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

2024-04-02 08:18

本文主要是介绍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;

 

NAME                                 TYPE                   VALUE

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

cpu_count                            integer                4

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 in 15.32 seconds

 

 

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

 

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

 

SQL> select * from v$px_process;

 

SERVER_NAME STATUS           PID SPID            SID    SERIAL#

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

P006        IN USE           100 19070982             35      50729

P001        IN USE            65 13107452            178      35585

P002        IN USE            73 9633888             184      25268

P003        IN USE            85 22478986            223      33339

P000        IN USE            63 18743314            500      16029

P004        IN USE            95 14221380            509      26446

P005        IN USE            99 23068708            510      20895

 

7 rows selected

 

 

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

 

//并行会话信息

SQL> select * from v$px_session;

 

SADDR   SID    SERIAL#      QCSID  QCSERIAL#      DEGREE REQ_DEGREE

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

070000007D2BA680        500      16029        324      26152           7   7

070000007FE7EC70        178      35585        324      26152           7   7

070000007FE6D5D0        184      25268        324      26152           7   7

070000007FDFC2C0        223      33339        324      26152           7   7

070000007D2A0490        509      26446        324      26152           7   7

070000007D29D620        510      20895        324      26152           7    7

070000007FC94480         35      50729        324      26152           7    7

070000007D12FB00        324      26152        324             

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

8 rows selected

 

 

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

 

 

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

 

 

//指定串行

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

PL/SQL procedure successfully completed

 

Executed in 46.816 seconds

 

 

效果清晰可见,从原来的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个并行度;

SQL> select * from v$px_session;

 

SADDR                   SID    SERIAL#      QCSID  QCSERIAL#

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

070000007FFF52E0        361       3123        324      26152 

070000007FE84950        176      50028        324      26152

070000007FE7EC70        178      35508        324      26152  

070000007FE0AAF0        218       5994        324      26152 

070000007D29D620        510      20829        324      26152 

070000007D2A0490        509      26391        324      26152 

070000007FC94480         35      50615        324      26152  

070000007FFFAFC0        359      32516        324      26152  

070000007D12FB00        324      26152        324            

 

9 rows selected

 

SQL> select * from v$px_process;

SERVER_NAME STATUS           PID SPID                    SID SERIAL#

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

P006        IN USE           100 19005590                         35      50615

P001        IN USE            69 19398710                        176      50028

P002        IN USE            73 9633968                         178      35508

P003        IN USE            85 23068694                        218       5994

P007        IN USE           102 18743298                        359      32516

P000        IN USE            66 14221352                        361       3123

P005        IN USE            99 21233884                        509      26391

P004        IN USE            95 19071188                        510      20829

 

8 rows selected

 

 

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

 

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

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

 

SQL_TEXT                        SQL_ID        VERSION_COUNT

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

insert /*+ parallel(t,8) */ into t select * from t   67wymm0jhw3gv             2

 

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_ID  67wymm0jhw3gv, child number 1

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

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

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,00 | PCWP |            |

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

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;

10039808 rows inserted

 

Executed in 87.813 seconds

 

 

对应的执行计划如下:

 

 

SQL> select sql_text, sql_id, version_count from v$sqlarea where sql_text like 'insert /*+ noparallel */%';

 

SQL_TEXT                                SQL_ID VERSION_COUNT

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

insert /*+ noparallel */ into t select * from t    9u0xcrr3bcjs1             1

 

Executed in 0.234 seconds

 

 

 

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

 

PLAN_TABLE_OUTPUT

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

SQL_ID  9u0xcrr3bcjs1, 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本质相同,就不加以累述了。

 

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

这篇关于Oracle并行操作——并行DML操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/869451

相关文章

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

Oracle修改端口号之后无法启动的解决方案

《Oracle修改端口号之后无法启动的解决方案》Oracle数据库更改端口后出现监听器无法启动的问题确实较为常见,但并非必然发生,这一问题通常源于​​配置错误或环境冲突​​,而非端口修改本身,以下是系... 目录一、问题根源分析​​​二、保姆级解决方案​​​​步骤1:修正监听器配置文件 (listener.

Java Multimap实现类与操作的具体示例

《JavaMultimap实现类与操作的具体示例》Multimap出现在Google的Guava库中,它为Java提供了更加灵活的集合操作,:本文主要介绍JavaMultimap实现类与操作的... 目录一、Multimap 概述Multimap 主要特点:二、Multimap 实现类1. ListMult

Python中文件读取操作漏洞深度解析与防护指南

《Python中文件读取操作漏洞深度解析与防护指南》在Web应用开发中,文件操作是最基础也最危险的功能之一,这篇文章将全面剖析Python环境中常见的文件读取漏洞类型,成因及防护方案,感兴趣的小伙伴可... 目录引言一、静态资源处理中的路径穿越漏洞1.1 典型漏洞场景1.2 os.path.join()的陷

Python使用Code2flow将代码转化为流程图的操作教程

《Python使用Code2flow将代码转化为流程图的操作教程》Code2flow是一款开源工具,能够将代码自动转换为流程图,该工具对于代码审查、调试和理解大型代码库非常有用,在这篇博客中,我们将深... 目录引言1nVflRA、为什么选择 Code2flow?2、安装 Code2flow3、基本功能演示

Python中OpenCV与Matplotlib的图像操作入门指南

《Python中OpenCV与Matplotlib的图像操作入门指南》:本文主要介绍Python中OpenCV与Matplotlib的图像操作指南,本文通过实例代码给大家介绍的非常详细,对大家的学... 目录一、环境准备二、图像的基本操作1. 图像读取、显示与保存 使用OpenCV操作2. 像素级操作3.

python操作redis基础

《python操作redis基础》Redis(RemoteDictionaryServer)是一个开源的、基于内存的键值对(Key-Value)存储系统,它通常用作数据库、缓存和消息代理,这篇文章... 目录1. Redis 简介2. 前提条件3. 安装 python Redis 客户端库4. 连接到 Re

Java Stream.reduce()方法操作实际案例讲解

《JavaStream.reduce()方法操作实际案例讲解》reduce是JavaStreamAPI中的一个核心操作,用于将流中的元素组合起来产生单个结果,:本文主要介绍JavaStream.... 目录一、reduce的基本概念1. 什么是reduce操作2. reduce方法的三种形式二、reduce

MySQL表空间结构详解表空间到段页操作

《MySQL表空间结构详解表空间到段页操作》在MySQL架构和存储引擎专题中介绍了使用不同存储引擎创建表时生成的表空间数据文件,在本章节主要介绍使用InnoDB存储引擎创建表时生成的表空间数据文件,对... 目录️‍一、什么是表空间结构1.1 表空间与表空间文件的关系是什么?️‍二、用户数据在表空间中是怎么