使用50个并行SQLPLUS会话以及批量收集LIMIT和FORALL更新表,其中包含500多万条记录

问题描述 投票:0回答:2

我是Oracle新手,我试图提高更新大表(500多万条记录)的性能 - 无论我尝试多少,它都会破坏性能。

我正在尝试使用50个并行SQLPLUS会话以及批量收集LIMIT和FORALL更新一个包含5亿条记录的表 - 这需要花费大量时间(经过时间:04:32:30.29)。

  CURSOR NIT_CURSOR IS
  SELECT SA_ROWID, NEW_TRX_1, NEW_TRX_2
  FROM NIT_SA
  WHERE MOD(DBMS_ROWID.rowid_block_number(SA_ROWID),&2) = &1;
Note: &2 is 50 where as &1 is number of instance invoked from shell between (0-49), 
SA_ROWID is acutal rowid from SA Table

现在,UPDATE语句如下:

  C_COMMIT         CONSTANT PLS_INTEGER := 10000;
  FETCH NIT_CURSOR BULK COLLECT INTO BLK_NIT_SA LIMIT C_COMMIT;     

  FORALL indx IN 1 .. BLK_NIT_SA.COUNT
  UPDATE SA
  SET INS_TRX_ID = BLK_NIT_SA(indx).NEW_TRX_1,
      UPD_TRX_ID = BLK_NIT_SA(indx).NEW_TRX_2
  WHERE ROWID = BLK_NIT_SA(indx).SA_ROWID;

KSH在50个并行SQLPLUS会话中调用此脚本:

typeset -A sqlFile
sqlFile[2.3.sql]=50
for counter_i in "${!sqlFile[@]}"
do
  for counter_j in {0..$((${sqlFile[$counter_i]}-1))}
  do
     sqlplus -s ${DATABASE_CONNECT} @${SQLFILE} "${SPOOLFILE}" ${sqlFile[$counter_i]} $counter_j &
  done
done

根据我的理解,因为我直接使用表SA的rowid,这将是访问行的最快方式,50个SQL Session实际上应该更快地处理数据,就像我的观察一样,我很快就会增加数量SQL Session的并行进程从50到100,每个进程的更新时间增加2小时,即从4.5小时增加到7.5小时。

我打算在1.5到2小时内完成它。不确定它是否真实。

有人可以帮我上面吗?

sql oracle plsql oracle11g oracle10g
2个回答
3
投票

5亿多条记录不是一个好主意,您可以告诉表格结构,以及需要更新的列。我们可以考虑以下选项:

  1. 如果需要动态计算表上的新值,那么我们可以在表的顶部创建一个视图,这样每当我们读取视图时,我们就可以获得所需的值。
  2. 创建新表并根据需要插入现有表中的所有数据(使用这些列的新值)并删除旧表,重命名新表

2
投票

将PL / SQL转换为单个SQL语句并使用语句并行性应该可以显着提高性能:

alter session enable parallel dml;

merge /*+ parallel(50) */ into sa using
(
    select sa_rowid, new_trx_1, new_trx_2
    from nit_sa
) nit_sa
on (sa.rowid = nit_sa.sa_rowid)
when matched then update set
    sa.ins_trx_id = nit_sa.new_trx_1,
    sa.upd_trx_id = nit_sa.new_trx_2;

以上陈述只会从表格中读取一次。 Oracle会自动将表分成称为粒度的表,不需要手动对表进行分区。

并行性在理论上很容易 - 只需添加一个提示,运行时间就可以提高一个数量级。但在实践中正确行事可能会非常棘手。并行性需要Enterprise Edition,足够的资源,合理的配置等。运行并行DML将锁定整个表,直到语句完成 - 同时没有其他DML可以在表上运行。 (虽然其他进程仍然可以从表中读取。)

© www.soinside.com 2019 - 2024. All rights reserved.