Oracle删除大表并回收空间的过程

如何删除大表中的数据

http://space.itpub.net/22664653/viewspace-704778
http://hi.baidu.com/ice_sky2008/blog/item/b4bd43fd4a45bb4cd6887da7.html
http://hemin108.iteye.com/blog/547282
http://hemin108.iteye.com/blog/547282
http://psoug.org/reference/truncate.html
http://www.njeit.cn/show.aspx?id=827&cid=65###
http://www.360doc.com/content/10/0317/13/925373_19114692.shtml

上一篇 / 下一篇  2011-08-12 22:33:11 / 个人分类:Oracle

查看( 77 ) / 评论( 0 ) / 评分( 0 / 0 )
通常我们认为truncate和drop都是ddl语句,都会释放表占用的空间,且不可回退;而他们的之间的区别在于我们平时忽略的reuse/drop storage子句.
reuse storage不会立即释放表的extent,我们可以先使用truncate table tableName reuse storage,然后分批释放表的extent.这在删除大表时非常有用,避免大量的io操作,影响整体性能.如果使用默认的drop storage就会立即释放extent,删除的表如果非常大,这对系统有时候这可能是灾难性的.
版本:10.2.0.1 
说明:在9i下如此操作为报错(后续说明)。
实验过程如下:
SQL> insert into yanga select * from yanga;
50474 rows created.
SQL> /
100948 rows created.
SQL> /
201896 rows created.
SQL> /
403792 rows created.
SQL> /
807584 rows created.
SQL> /
1615168 rows created.
SQL>  select sum(bytes)/1024/1024 MB from dba_segments where segment_name=UPPER('yanga');
        MB
----------
       349
SQL>  truncate table yanga reuse storage;
Table truncated.
SQL>  select sum(bytes)/1024/1024 MB from dba_segments where segment_name=UPPER('yanga');
        MB
----------
       349
SQL>alter table yanga deallocate unused keep 50M;
Table altered.
SQL>  select sum(bytes)/1024/1024 MB from dba_segments where segment_name=UPPER('yanga');
        MB
----------
   50.0625
SQL>alter table yanga deallocate unused keep 10M;
Table altered.
SQL>  select sum(bytes)/1024/1024 MB from dba_segments where segment_name=UPPER('yanga');
        MB
----------
   10.0625
SQL>alter table yanga deallocate unused keep 0 M;
Table altered.
SQL>  select sum(bytes)/1024/1024 MB from dba_segments where segment_name=UPPER('yanga');
        MB
----------
     .0625
SQL>drop table yanga purge;
Table dropped.
SQL>  select sum(bytes)/1024/1024 MB from dba_segments where segment_name=UPPER('yanga');
        MB
----------
以上是10g2的操作。




http://www.cnblogs.com/killkill/archive/2009/06/30/1514015.html

近日在查询某项日志的时候,发现查询非常缓慢,根据以往的经验这是由于某个日志表过大引起的,为了加快查询,决定将大部分的历史数据迁移到另外一个表中,本文主要记录删除这个大表的过程,就解决问题而言还有很多方法,但是本文侧重点在于如何处理大数据量删除的操作,及其善后工作。

首先看看我们要做数据迁移的表所占的空间:

SQL> select segment_name , bytes/1048576 MB
  2  from user_segments
  3  order by bytes
  4  /

SEGMENT_NAME                                               MB
-------------------------------------------------- ----------
TAB_NODE_PARAM                                           .375
SYS_LOB0000053047C00004$$                               .4375
PK_TAB_FLOW_HIS                                             1
PK_TAB_NODE_HIS                                             2
TAB_TASK_HIS                                                2
TAB_FLOW_HIS                                                4
TAB_NODE_HIS                                               17
PK_TAB_APPEXCHANGE_LOG                                    152
TAB_APPEXCHANGE_LOG                                       768

看看历史数据大概所占的空间比例:

SQL> select count(*) from tab_appexchange_log
  2  where receive_time >= to_date('2009-01-01','yyyy-mm-dd')
  3  union all
  4  select count(*) from tab_appexchange_log
  5  where receive_time < to_date('2009-01-01','yyyy-mm-dd')
SQL> /

  COUNT(*)
----------
   1584298
   4037710

从结果来看,的确存在很多历史数据,我们将 2009 年之前的数据迁移到别的表中。

SQL> create table tab_appexchange_log_20090101
  2  as
  3  select * from tab_appexchange_log
  4  where receive_time < to_date('2009-01-01','yyyy-mm-dd')
SQL> /

Table created.

SQL> select count(*) from tab_appexchange_log_20090101
  2  /

  COUNT(*)
----------
   4037710

数据已经迁移一份到新的表里面了,可以删除原表中的旧数据了。

SQL> delete tab_appexchange_log where receive_time < to_date('2009-01-01','yyyy-mm-dd')
  2  /
delete tab_appexchange_log where receive_time < to_date('2009-01-01','yyyy-mm-dd')
       *
ERROR at line 1:
ORA-30036: unable to extend segment by 8 in undo tablespace 'UNDOTBS2'

这里出现了一个 ORA-30036的错误,大概意思是undo表空间不足,看来是要删除的数据太多了,于是考虑化整为零,删一点,commit一下。

 

SQL> delete tab_appexchange_log where receive_time < to_date('2007-01-01','yyyy-mm-dd')
  2  /

0 rows deleted.

SQL> delete tab_appexchange_log where receive_time < to_date('2008-01-01','yyyy-mm-dd')
  2  /

1586227 rows deleted.

SQL> commit;

Commit complete.

SQL> delete tab_appexchange_log where receive_time < to_date('2008-06-01','yyyy-mm-dd')
  2  /

813019 rows deleted.

SQL> commit;

Commit complete.

SQL> delete tab_appexchange_log where receive_time < to_date('2009-01-01','yyyy-mm-dd')
  2  /

1638464 rows deleted.

SQL> commit;

Commit complete.

可以预知,现在表里面的数据应该只有 15***** 条,以下证实了这个想法。

SQL> select count(*) from tab_appexchange_log
  2  /

  COUNT(*)
----------
   1584522

我们再看看表占用空间的情况:

SQL> select segment_name , bytes/1048576 MB
  2  from user_segments
  3  order by bytes asc;

SEGMENT_NAME                                               MB
-------------------------------------------------- ----------
TAB_NODE_PARAM                                           .375
SYS_LOB0000053047C00004$$                               .4375
PK_TAB_FLOW_HIS                                             1
PK_TAB_NODE_HIS                                             2
TAB_TASK_HIS                                                2
TAB_FLOW_HIS                                                4
TAB_NODE_HIS                                               17
PK_TAB_APPEXCHANGE_LOG                                    152
TAB_APPEXCHANGE_LOG_20090101                              552
TAB_APPEXCHANGE_LOG                                       768

看来原表所占的空间还没有释放,这个涉及一个HWM的说法,还有可以观察到在TAB_APPEXCHANGE_LOG上面的一个索引 PK_TAB_APPEXCHANGE_LOG 空间没有回收。

我们回过头来看看刚才的操作对undo表空间产生的压力:

TO_CHAR(BEGIN_TIME, TO_CHAR(END_TIME,'Y   UNDOBLKS
------------------- ------------------- ----------
2009-06-30 13:39:32 2009-06-30 13:46:35      96164
2009-06-30 13:29:32 2009-06-30 13:39:32      89316
2009-06-30 13:19:32 2009-06-30 13:29:32     209885
2009-06-30 13:09:32 2009-06-30 13:19:32        105
2009-06-30 12:59:32 2009-06-30 13:09:32        125
2009-06-30 12:49:32 2009-06-30 12:59:32         74
2009-06-30 12:39:32 2009-06-30 12:49:32         80
2009-06-30 12:29:32 2009-06-30 12:39:32         72
2009-06-30 12:19:32 2009-06-30 12:29:32         76
2009-06-30 12:09:32 2009-06-30 12:19:32         89
2009-06-30 11:59:32 2009-06-30 12:09:32        126

呵呵,刚才DML的操作对undo表空间产生的压力还是非常可观的。

我们开始回收表所占的空间:

SQL> alter table TAB_APPEXCHANGE_LOG enable row movement;

Table altered.

SQL> alter table TAB_APPEXCHANGE_LOG shrink space;

Table altered.

 

由于这么大规模的删除,会导致很多索引中存在很多标记为删除的节点,占地方还不能发挥作用,因此重建索引将这些无用节点清理出去才是上策。

SQL> analyze index PK_TAB_APPEXCHANGE_LOG  validate structure;

Index analyzed.

SQL> select height, name , LF_ROWS_LEN,LF_ROWS,DEL_LF_ROWS,DEL_LF_ROWS_LEN from index_stats;

    HEIGHT NAME                           LF_ROWS_LEN    LF_ROWS DEL_LF_ROWS DEL_LF_ROWS_LEN
---------- ------------------------------ ----------- ---------- ----------- ---------------
         3 PK_TAB_APPEXCHANGE_LOG            88905533    5621608     4036429        63558680

SQL> alter index PK_TAB_APPEXCHANGE_LOG rebuild online;

Index altered.

SQL> analyze index PK_TAB_APPEXCHANGE_LOG  validate structure;

Index analyzed.

SQL> select height, name , LF_ROWS_LEN,LF_ROWS,DEL_LF_ROWS,DEL_LF_ROWS_LEN from index_stats;

    HEIGHT NAME                           LF_ROWS_LEN    LF_ROWS DEL_LF_ROWS DEL_LF_ROWS_LEN
---------- ------------------------------ ----------- ---------- ----------- ---------------
         3 PK_TAB_APPEXCHANGE_LOG            25347109    1585195           0               0

如果现在我们再查一下索引所占的空间的话,会发现所占空间是没有减少的,和表一样,同样也是需要收缩一下空间。

SQL> alter index PK_TAB_APPEXCHANGE_LOG shrink space;

Index altered.

SQL> select segment_name , bytes/1048576 MB
  2  from user_segments
  3  order by bytes
  4  /

SEGMENT_NAME                                               MB
-------------------------------------------------- ----------
TAB_NODE_PARAM                                           .375
SYS_LOB0000053047C00004$$                               .4375
PK_TAB_FLOW_HIS                                             1
TAB_TASK_HIS                                                2
PK_TAB_NODE_HIS                                             2
TAB_FLOW_HIS                                                4
TAB_NODE_HIS                                               17
PK_TAB_APPEXCHANGE_LOG                                28.1875
TAB_APPEXCHANGE_LOG                                  220.8125
TAB_APPEXCHANGE_LOG_20090101                              552

 

自此一次删除大表的操作完成,回顾一下,主要有以下几点:

1。分批删除数据,按批次提交。

2。回收表所占的空间。

3。处理由于表收缩所导致的索引失效问题。


http://psoug.org/reference/truncate.html

drop table与db cache


我们都知道drop table, truncate table时都会先做一次checkpoint,将被删除对象的脏块写入磁盘。

客户有一套系统,Oracle 9.2.0.8,需要做数据迁移,由于种种原因,采用的是逻辑迁移的方式。由于库比较大,超过了1.5T,而停机时间又有限,因此在正式迁移之前需要做大量的测试,测试的目的,一方面是看迁移流程上是否存在问题,另一方面是看迁移的时候,哪个地方会存在性能瓶颈,并进行优化,同时估算实施迁移时间。

第一次测试后,需要把测试产生的大量用户及其对象全部删除,删除用的是drop user username cascade。不幸的是这种方式删除得相当地慢。一个9000多个表的用户,删除了1个半小时才删除了4000多个表。为什么这么慢?有没有办法提高速度?

drop table既然要做checkpoint,那么在db cache非常大的情况下,这需要消耗的时间是比较长的。如果能够减少这个时间无疑将大幅提高速度。首先尝试做一次checkpoint,将buffer cache全部刷新出去:

view plain copy to clipboard print ?
  1. alter system checkpoint;   
  2. alter session set events 'immediate trace name flush_cache level 1';  
alter system checkpoint;
alter session set events 'immediate trace name flush_cache level 1';

发现没什么效果。

由于db_cache_size有50GB左右,db_keep_cache_size有6G左右。重新设置参数,将db_keep_cache_size设为0,将db_cache_size设为200M,重启一下数据库,重新执行删除用户的操作,操作很快完成。

在另一次同样的过程中,采用同样的修改参数的方式,效果同样非常明显。

这是个简单的案例,与君共享。


http://www.laoxiong.net/drop-table-and-db-cache.html

http://caihorse.iteye.com/blog/614570

http://psoug.org/reference/truncate.html

« Control SCN of Undo Segments | Blog首页 | Jonathan Lewis: Can we have a sensible debate ? »

Oracle中大批量删除数据的方法

站内相关文章|Related Articles
Oracle中审计删除(DELETE)操作的触发器
dbms_sqltune解析SQL的BIND_DATA绑定变量值
SQL 共享之 ROLL_INVALID_MISMATCH 含义
CBO中 SMON 进程与 col_usage$ 的维护
10g临时表空间组导致递归SQL高度解析案例
批量删除海量数据通常都是很复杂及缓慢的,方法也很多,但是通常的概念是:分批删除,逐次提交。
下面是我的删除过程,我的数据表可以通过主键删除,测试过Delete和For all两种方法,for all在这里并没有带来性能提高,所以仍然选择了批量直接删除。

首先创建一下过程,使用自制事务进行处理:
create or replace procedure delBigTab
(
p_TableName       in    varchar2,
p_Condition       in    varchar2,
p_Count        in    varchar2
)
as
pragma autonomous_transaction;
n_delete number:=0;
begin
while 1=1 loop
EXECUTE IMMEDIATE
'delete from '||p_TableName||' where '||p_Condition||' and rownum <= :rn'
USING p_Count;
if SQL%NOTFOUND then
exit;
else
n_delete:=n_delete + SQL%ROWCOUNT;
end if;
commit;
end loop;
commit;
DBMS_OUTPUT.PUT_LINE('Finished!');
DBMS_OUTPUT.PUT_LINE('Totally '||to_char(n_delete)||' records deleted!');
end;


以下是删除过程及时间:
SQL> create or replace procedure delBigTab
  2  (
  3    p_TableName       in    varchar2,
  4    p_Condition       in    varchar2,
  5    p_Count        in    varchar2
  6  )
  7  as
  8   pragma autonomous_transaction;
  9   n_delete number:=0;
 10  begin
 11   while 1=1 loop
 12     EXECUTE IMMEDIATE
 13       'delete from '||p_TableName||' where '||p_Condition||' and rownum <= :rn'
 14     USING p_Count;
 15     if SQL%NOTFOUND then
 16        exit;
 17     else
 18              n_delete:=n_delete + SQL%ROWCOUNT;
 19     end if;
 20     commit;
 21   end loop;
 22   commit;
 23   DBMS_OUTPUT.PUT_LINE('Finished!');
 24   DBMS_OUTPUT.PUT_LINE('Totally '||to_char(n_delete)||' records deleted!');
 25  end;
 26  /

Procedure created.

SQL> set timing on
SQL> select min(NUMDLFLOGGUID) from HS_DLF_DOWNLOG_HISTORY;

MIN(NUMDLFLOGGUID)
------------------
          11000000

Elapsed: 00:00:00.23
SQL> exec delBigTab('HS_DLF_DOWNLOG_HISTORY','NUMDLFLOGGUID < 11100000','10000');

PL/SQL procedure successfully completed.

Elapsed: 00:00:18.54
SQL> select min(NUMDLFLOGGUID) from HS_DLF_DOWNLOG_HISTORY;

MIN(NUMDLFLOGGUID)
------------------
          11100000

Elapsed: 00:00:00.18
SQL> set serveroutput on
SQL> exec delBigTab('HS_DLF_DOWNLOG_HISTORY','NUMDLFLOGGUID < 11200000','10000');
Finished!
Totally 96936 records deleted!

PL/SQL procedure successfully completed.

Elapsed: 00:00:18.61
10万记录大约19s

SQL> exec delBigTab('HS_DLF_DOWNLOG_HISTORY','NUMDLFLOGGUID < 11300000','10000');
Finished!
Totally 100000 records deleted!

PL/SQL procedure successfully completed.

Elapsed: 00:00:18.62
SQL> exec delBigTab('HS_DLF_DOWNLOG_HISTORY','NUMDLFLOGGUID < 11400000','10000');
Finished!
Totally 100000 records deleted!

PL/SQL procedure successfully completed.

Elapsed: 00:00:18.85
SQL> 
SQL> exec delBigTab('HS_DLF_DOWNLOG_HISTORY','NUMDLFLOGGUID < 13000000','10000');
Finished!
Totally 1000000 records deleted!

PL/SQL procedure successfully completed.

Elapsed: 00:03:13.87

100万记录大约3分钟
SQL> exec delBigTab('HS_DLF_DOWNLOG_HISTORY','NUMDLFLOGGUID < 20000000','10000');
 
Finished!
Totally 6999977 records deleted!

PL/SQL procedure successfully completed.

Elapsed: 00:27:24.69
700万大约27分钟

以上过程仅供参考.


http://www.eygle.com/archives/2005/04/oracleoeouaeeae.html



你可能感兴趣的:(Oracle删除大表并回收空间的过程)