Oracle 根据条件大量删除数据

*爱你&永不变心* 提交于 2020-03-01 05:44:36

金蝶BOS里系统表 t_bas_message 表用于存放系统消息.实际操作中,客户端默认15分钟查询一次是否有新消息

用户基本不会去删除已读的消息,这就导致这张表大得惊人,系统运行一年多以来,大约有 4500万条数据.再加上这张表上存在索引,对数据库而言,一旦操作失误导致表中索引失效,数据库会因为全表扫描太多彻底卡死.

之后考滤删除一个月以前的数据执行SQL语句如下

DELETE FROM t_bas_message t WHERE t.fsendtime > Sysdate-30;

这段代码在测试库运行了两个多小时.一方面是数据量很大,另一方面是因为表中有几列索引.实际中这种方案肯定不行.


跟DBA讨论了一下,有两种方案.

A 通过表分区操作.通过表进行分区,然后直接删除无关分区.代码如下

-- 创建中间表,添加主键,索引,分区等信息
create table T_BAS_MESSAGE_bak
(
  fid                VARCHAR2(44) not null
)
partition by range (fsendtime)
(
  partition PART_20141201 values less than (TIMESTAMP' 2014-12-01 00:00:00'),
  partition PART_MAX values less than (MAXVALUE)
);
--验证是否可以操作
CALL dbms_redefinition.can_redef_table('HLWL','T_BAS_MESSAGE');
--开始重定义
CALL dbms_redefinition.start_redef_table('HLWL', 'T_BAS_MESSAGE', 'T_BAS_MESSAGE_bak');
--同步表结构(这段只能在SQLPlus下执行,所以注掉了)
--set serverout on;
--declare
--  retval   number(5);
--begin
--  dbms_redefinition.copy_table_dependents (user,'bo_cr_sales_vbillcode','bo_cr_sales_vbillcode_20141111',ignore_errors=>TRUE,num_errors=>retval);
--  dbms_output.put_line(retval);
--end;
--/
--
--同步数据
CALL dbms_redefinition.sync_interim_table('HLWL', 'T_BAS_MESSAGE', 'T_BAS_MESSAGE_bak');
--在线重定义表
CALL dbms_redefinition.finish_redef_table('HLWL', 'T_BAS_MESSAGE', 'T_BAS_MESSAGE_bak');
--删除中间表
DROP TABLE T_BAS_MESSAGE_bak;
--彻底删除表分区(这里用表分区快速删除数据)
ALTER TABLE T_BAS_MESSAGE DROP PARTITION PART_20150101;
--删除表分区后添加约束,索引,如果放在前面,删除会区会导致全局索引失效,包括主键索引
alter table T_BAS_MESSAGE add constraint PK_BAS_MCMESSAGE primary key (FID);
--重新采集表信息
CALL dbms_stats.gather_table_stats('HLWL','T_BAS_MESSAGE');


B 把有用的数据转移到一张表,然后Drop 掉原表.重新创建原表后导入数据.代码如下

--t.fsender_l1<>'administrator'  包括 AND t.fsender_l1 is not null
CREATE TABLE t_bas_message_bak AS SELECT * FROM  t_bas_message t WHERE t.fsendtime> Sysdate-30 AND t.fsender_l1<>'administrator';
DROP TABLE t_bas_message;
CREATE TABLE t_bas_message AS SELECT * FROM  t_bas_message_bak;
create index IX_MESSAGE_TEXT on T_BAS_MESSAGE (FRECEIVER, FORGID);
create index IX_MSG_RECEIVER on T_BAS_MESSAGE (FRECEIVER);
create index IX_MSG_SOURCE on T_BAS_MESSAGE (FSOURCEID);
alter table T_BAS_MESSAGE
add constraint PK_BAS_BMCMESSAGE primary key (FID);
DROP TABLE t_bas_message_bak;

PS:这里的三个索引,是原表就有的,所以加上.但实际上我认为,第一个组合索引在Oracle 中完全取代了第二个索引,应该去掉的.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!