【问题标题】:Parallel executions of stored procedure using Nested table使用嵌套表并行执行存储过程
【发布时间】:2020-11-05 03:03:48
【问题描述】:

我在存储过程和 FORALL 语句中使用嵌套表来加速过程执行,这需要将近 30 分钟的运行时间,当我从单个系统执行过程时,执行速度很快,我能够获得所需的输出.

问题是当从多个系统同时并行执行相同的过程时,结果是错误的。假设行为是数据同时插入到同一个嵌套表中,但我不确定如何获得正确的结果或如何操作嵌套表的行为。

先创建一个对象:

create or replace TYPE JR_Type AS OBJECT

(
"JOB_ID" NUMBER(38,0), 
    "E_ID" NCHAR(64), 
    "USER_NAME" NCHAR(32), 
    "START_TIME" TIMESTAMP (6), 
    "END_TIME" TIMESTAMP (6), 

);

在这个对象上创建一个嵌套表。

create or replace TYPE JR_Table AS TABLE OF JR_Type ;

下面是我在程序中使用的方式:

我的程序很大,但我以更简单的方式使用以下方式。

create or replace Procedure data_test (E in nchar, J in number)
      AS

      Exec_data JR_Table;   //Created a nested table variable
      
      BEGIN
      
    select JR_Type (job_id, e_id,  USER_NAME, start_time, end_time)
                    bulk collect into Exec_data   //Bulk collect into this variable
                    from ( taBLE);
                    
                    
                     FORALL counter in Exec_data.first..Exec_data.last    //insert using FORALL
                insert into DATA_TEMP1 Values
                (Exec_data(counter).JOB_ID, Exec_data(counter).E_ID, Exec_data(counter).START_TIME, Exec_data(counter).END_TIME;
    
                commit;
                
                End;

我确信他们应该是处理这个问题的一种方法,但不幸的是,这超出了我的理解,希望我能得到一些帮助。

编辑---------------------------------------------- ---------------------

2 次执行在同一个表中插入数据,FYI 输入数据在 2 次执行中不同。

total records should be 120

1st execution 74

2nd execution 56

有了这个设计记录会根据执行而变化,一旦我得到 80 或 90 0r 60。

【问题讨论】:

  • 当你说结果是错误的,你是什么意思?您正在并行运行相同的过程,我猜输入参数不同,但我没有看到输入参数和嵌套表之间有任何关系
  • @RobertoHernandez 是的输入参数是不同的关系这里取决于输入参数查询将获取数据并存储在嵌套表中,在这种情况下,来自两个输入参数的数据被合并或覆盖,结果不是预期的。我假设当程序从第二个系统并行执行时,数据正在替换已经从第一个系统执行插入的数据,最终结果将是错误数据,我需要一种并行执行数据应该单独存储的方法,并且应该被显示而不被覆盖。
  • 那么您的事务中需要隔离级别。
  • 好的,这是一个新概念,你能解释一下在这种情况下它是如何工作的吗?
  • 我给你一个带有解释的答案。我认为它可能会解决您的问题

标签: oracle parallel-processing nested-table


【解决方案1】:

当您评论并发访问问题时,解决此问题的一种方法是应用不同的 ISOLATION_LEVEL,在本例中为 SERIALIZABLE。如果不指定隔离级别,则默认为 READ COMMITED,这意味着每个查询只能看到在查询开始之前提交的数据,而不是事务开始。但是,它不会阻止其他事务修改查询读取的数据。因此,其他事务可能会在查询执行之间更改数据。多次执行给定查询的任何事务都可能遇到不可重复读取或幻像。

使用 SERIALIZABLE 事务隔离级别,只有在事务开始时提交的数据以及事务本身通过 INSERT、UPDATE 和 DELETE 生成的数据才能被查询访问,因此 查询不会查看其他进程提交的任何其他数据。

create or replace Procedure data_test (E in nchar, J in number)
AS

      Exec_data JR_Table;   //Created a nested table variable
      
      BEGIN
          -- set isolation level ( only the data manipulated here will be available to this process
    EXECUTE IMMEDIATE '  ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE ' ; -- session level 
  SET TRANSACTION LEVEL SERIALIZABLE; -- transaction level
    select JR_Type (job_id, e_id,  USER_NAME, start_time, end_time)
                    bulk collect into Exec_data   //Bulk collect into this variable
                    from ( taBLE);
                    
                    
                     FORALL counter in Exec_data.first..Exec_data.last    //insert using FORALL
                insert into DATA_TEMP1 Values
                (Exec_data(counter).JOB_ID, Exec_data(counter).E_ID, Exec_data(counter).START_TIME, Exec_data(counter).END_TIME;
    
                commit;
                
                End;

你可以使用

ALTER SESSION SET ISOLATION LEVEL xxx -- 影响会话行为

SET TRANSACTION LEVEL xxx -- 影响交易本身

【讨论】:

  • 感谢您的回答,我今天完成了,明天测试并接受它
  • 一个问题,这个变化会影响程序的执行时间吗?
  • 我不这么认为,但是在应用隔离时要小心。我给你两种方式,一种从那一刻起影响整个会话,另一种影响交易。我会先在您的程序中使用 SET TRANSACTION LEVEL 对其进行测试
  • 我试过你的解决方案,通过使用set transaction level 结果没有改变,通过使用session level 会话进入死锁状态,应该在30秒内执行的程序没有退出一分钟后。他们有什么其他方式我可以做到这一点,或者这甚至可能吗?
  • 你能把两个进程同时运行的结果放在问题里吗?你得到什么输出?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-11
  • 2021-08-25
  • 1970-01-01
  • 2016-03-19
  • 2018-03-12
  • 2019-03-02
相关资源
最近更新 更多