oracle上亿条记录大表delete

本文介绍了一种使用Oracle DBMS_JOB并行处理大量数据删除的方法,通过创建多个job并分配特定范围的数据来提升效率。此外,还讨论了INSERT、UPDATE及DELETE操作的日志产生量,并提出在大量数据操作时使用INSERT替代UPDATE的建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

delete /*+ use_hash(a,b) parallel(a,15)*/ from tabacca where exists (select 1 from temptablea b where a.id=b.id and b.type='1');

 

可以试试多个job分工,同时进行。
比如开10个job,每个job分十万数据

 

DECLARE
   x   NUMBER;
BEGIN
   FOR i IN 0 .. 9
   LOOP
      DBMS_JOB.submit (
         x,
         'begin DELETE   tabacca t1
 WHERE   EXISTS
            (SELECT   1
               FROM   (SELECT   id
                         FROM   (SELECT   SUBSTR (TO_CHAR (ROWNUM), -1) rn,
                                          id
                                   FROM   temptablea
                                  WHERE   TYPE = ''1'')
                        WHERE   rn = '''
         || i
         || ''') t2
              WHERE   t2.id = t1.id);

COMMIT; end;'
      );
   END LOOP;
END;

分区表的话,就加一层分区进行循环。

for 分区
  for i in 0.. 9

 

DBMS_JOB.SUBMIT(:jobno,//job号  
                                     'your_procedure;',//要执行的过程  
                                     trunc(sysdate)+1/24,//下次执行时间  
                                     'trunc(sysdate)+1/24+1'//每次间隔时间  
                                   );  
     删除job:dbms_job.remove(jobno);  
     修改要执行的操作:job:dbms_job.what(jobno,what);  
     修改下次执行时间:dbms_job.next_date(job,next_date);  
     修改间隔时间:dbms_job.interval(job,interval);  
     停止job:dbms.broken(job,broken,nextdate);  
     启动job:dbms_job.run(jobno);  

附:调用语句和参数说明:  

dbms_job.submit( job out binary_integer,

what       in   archar2,
next_date     in   date,
interval     in   varchar2,
no_parse     in   boolean)
其中:
●    job:输出变量,是此任务在任务队列中的编号;
●    what:执行的任务的名称及其输入参数;
●    next_date:任务执行的时间;
●    interval:任务执行的时间间隔

 

 

ORACLE的INSERT、UPDATE和DELETE在执行过过程中都是会产生日志的,因此,当插入大量数据的时候可以添加“nologging”选项,以提高执行速度,三种操作所做的具体东西而相关资料是这样写的:
      常INSERT产生最少的Undo,Update产生的Undo居中,而Delete操作产生的Undo最多。
      对于INSERT操作,回滚段只需要记录插入记录的rowid,如果回退,只需将该记录根据rowid删除即可;
      对于UPDATE操作,回滚段只需要记录被更新字段的旧值即可(前镜像),回退时通过旧值覆盖新值即可完成回退;
      对于DELETE操作,Oracle则必须记录整行的数据,在回退时,Oracle通过一个反向操作恢复删除的数据。
  因此INSERT是最快的
  所以当遇到大量数据修改的时候,可以考虑用INSERT来代替UPDATE。
 
  例子:
    有一个表A有100万条记录,我现在要把这个表A备份成另外一个表B。我用了两种方式
    create table b as select * from a
    第二种是
    create table b as select * from a where 1=0    可以加上(alter table b nologging)
    insert into b select * from a
    这两种速度,差别是十几倍。为什么啊?

 

    第一种属于ddl语句,不产生redo,日志量小

   而第二种用到的insert 属于dml,产生日志,由于记录多,产生的redo量也是很大的,还要写很多log

 

 

 

 

 

 

<think>好的,我现在要处理用户的问题,关于Oracle数据库中超过一亿条记录执行DELETE操作产生量日志的情况。首先,我需要理解用户的问题背景。用户可能遇到了在执行规模删除操作时,产生了过多的redo日志,导致存储压力增,或者影响了数据库的性能。他们想知道为什么会这样,以及有什么解决办法。 首先,我应该回忆一下Oracle的redo日志机制。DELETE操作属于DML操作,会生成量的redo日志,尤其是在处理量数据时。每个被删除的行都会在redo日志中记录,以确保事务的持久性和恢复能力。对于一亿条记录来说,逐行删除会产生海量的日志条目,这不仅会消耗量的日志空间,还可能导致日志切换频繁,影响系统性能。 接下来,用户可能需要知道为什么DELETE会产生这么多日志。这里需要解释Oracle的redo生成机制,特别是对于事务的处理。此外,可能需要比较DELETE、TRUNCATE和DROP的区别,因为后两者是DDL操作,生成的redo较少,但TRUNCATE会立即释放空间,而DELETE不会,除非使用其他操作。 然后,用户可能想知道如何减少这种情况下的日志量。可能的解决方案包括分批删除、使用NOLOGGING选项(但要注意风险)、或者使用分区来分阶段删除数据。另外,可以考虑使用临时或CTAS(Create Table As Select)的方式来保留需要的数据,而不是直接删除量数据。 还需要考虑事务的小。如果一次性删除一亿条记录,事务会很,可能导致UNDO空间不足,或者长时间锁,影响其他操作。分批提交可以缓解这个问题,减少每次事务的日志量,同时释放锁和UNDO空间。 另外,可能需要提醒用户关于备份和恢复的问题。使用NOLOGGING操作可能会影响数据库的恢复能力,所以需要确保有其他的备份策略。同时,高水位线的处理也是一个问题,DELETE操作不会重置高水位线,可能导致查询性能下降,这时候可能需要使用MOVE或TRUNCATE来回收空间。 可能还需要提到并行DML(PDML)的使用,通过并行处理来加快删除速度,但同样需要考虑系统资源的情况。此外,如果数据确实不需要了,可以考虑物理删除而不是逻辑删除,比如使用分区交换或直接删除分区,这对分区特别有效。 最后,总结一下,用户的问题核心在于如何高效、减少日志地删除海量数据。需要综合考虑日志生成机制、事务管理、结构设计(如分区)、以及替代方法等多个方面,给出切实可行的建议,并提醒相关的注意事项,比如备份、性能影响等。</think>在Oracle数据库中,对超过1亿条记录执行`DELETE`操作时,确实会产生量Redo日志和Undo日志,主要原因及优化方案如下: --- ### **1. 为什么会产生量日志?** - **Redo日志**:Oracle为保证事务的持久性,所有数据修改操作(包括`DELETE`)都会生成Redo日志。删除1亿条记录时,每条记录的删除操作都会被记录到Redo日志中。 - **Undo日志**:为支持事务回滚和一致性读,Oracle会为每条被删除的记录生成Undo数据。 - **事务小**:一次性删除1亿条记录属于超事务,会长时间占用Undo空间,并导致Redo日志暴增。 --- ### **2. 直接影响** - **日志空间压力**:可能导致Redo日志组频繁切换,甚至因日志空间不足而报错(ORA-00362)。 - **性能下降**:量日志写入和归档操作会消耗I/O和CPU资源。 - **锁争用**:长时间运行的事务可能阻塞其他操作(如DML或DDL)。 --- ### **3. 优化方案** #### **(1) 分批删除(推荐)** 通过分批次提交事务,减少单次事务的日志量和锁持有时间: ```sql BEGIN LOOP DELETE FROM big_table WHERE [condition] AND ROWNUM <= 10000; -- 每批删除1万条 EXIT WHEN SQL%ROWCOUNT = 0; COMMIT; -- 分批提交释放Undo和Redo压力 END LOOP; END; ``` #### **(2) 使用`NOLOGGING`(谨慎使用)** - **适用场景**:如果数据可重建且无需恢复。 - **操作步骤**: ```sql ALTER TABLE big_table NOLOGGING; -- 设置为NOLOGGING DELETE FROM big_table WHERE [condition]; -- 删除操作(仍需生成Undo) ALTER TABLE big_table LOGGING; -- 恢复LOGGING ``` - **风险**:NOLOGGING模式下部分操作可能无法通过Redo恢复,需确保有备份。 #### **(3) 转换为`TRUNCATE`或`DROP`** - **适用场景**:删除全数据或分区数据。 - **优势**:`TRUNCATE`/`DROP`是DDL操作,几乎不生成Redo/Undo。 - **限制**:无法指定条件删除部分数据。 - **示例**: ```sql TRUNCATE TABLE big_table; -- 清空全 ALTER TABLE big_table DROP PARTITION p1; -- 删除分区(需分区) ``` #### **(4) 重建(CTAS)** - **适用场景**:保留少量数据时,通过新建跳过不需要的数据。 - **步骤**: ```sql CREATE TABLE new_table NOLOGGING AS SELECT * FROM big_table WHERE [condition_to_keep]; DROP TABLE big_table; RENAME new_table TO big_table; -- 重建索引、约束等 ``` - **优势**:速度快,日志少,同时重置高水位线(HWM)。 #### **(5) 启用并行DML(PDML)** - **适用场景**:充分利用硬件资源加速删除。 - **步骤**: ```sql ALTER SESSION ENABLE PARALLEL DML; DELETE /*+ PARALLEL(big_table, 8) */ FROM big_table WHERE [condition]; COMMIT; ``` - **注意**:需评估系统CPU和I/O资源是否充足。 #### **(6) 分区优化** - **策略**:按时间或范围分区,直接`TRUNCATE`或`DROP`分区。 - **示例**: ```sql -- 按日期分区,直接删除历史分区 ALTER TABLE big_table DROP PARTITION sales_2022; ``` --- ### **4. 注意事项** 1. **备份**:任何规模数据操作前,建议备份或数据库。 2. **高水位线(HWM)**:`DELETE`不会重置HWM,需后续通过`ALTER TABLE SHRINK`或`MOVE`回收空间。 3. **归档模式**:若数据库处于归档模式,需监控归档日志空间。 4. **替代方案**:考虑使用外部或数据泵导出/导入。 --- ### **总结** 对超规模的删除操作,优先选择**分批删除**、**分区**或**重建(CTAS)**。若允许数据不可恢复,可尝试`NOLOGGING`,但需权衡风险。最终方案需结合业务需求(是否允许停机、是否需要恢复等)和硬件资源综合选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值