br1*_*337 2 sql oracle plsql delete-row
我有一组表,其中主表有150万行.其中一个子项也接近100万行.
主表的数据也必须复制到历史表中.我写了一个PLSQL脚本来首先删除子行和子行,但这个过程耗时太长,接近12小时.
我正在使用批量收集来删除数据.
该脚本将在每天星期一凌晨3点由Java调度程序调用.
我认为在第一次批量删除(有百万行)之后,该过程将很快,因为数据库每周只会增长近30k个寄存器.
解决这个问题的最佳解决方案是什么?
通常,从表中"删除"大量行的最快方法是将它们存储在临时表中,截断表并重新插入它们:
create table tempt as
select *
from t
where . . .;
truncate table t;
insert into t
select *
from tempt;
Run Code Online (Sandbox Code Playgroud)
这适用于一个表,它不会级联删除.根据触发器的设置方式,数据可能会更改(例如插入时间).您的问题没有提供足够的信息.
但是,理论上,您可以在子表上继续此过程:
create table tempchild as
select *
from child
where child.parentid in (select id from t);
truncate table child;
insert into child
select *
from tempchild;
Run Code Online (Sandbox Code Playgroud)
这是实现这一目标的快速方法的概述.如果您有可能影响不同表中记录之间关系的触发器和约束,则会变得更复杂.
如果没有您要删除的表的解释,与其相关的表以及所有这些表上的索引,则无法说明为什么这些删除需要花费这么长时间.有人想到 - 如果你有一个从一个表到另一个表的外键,那么外键关系中涉及的字段应该在两个表上建立索引.例如,假设您有以下表格:
PARENT_TABLE (1,000,000 rows)
ID_PARENT NUMBER PRIMARY KEY
SOMETHING VARCHAR2(10)
SOMETHING_ELSE NUMBER
VALUE_FIELD VARCHAR2(20) REFERENCES VALID_VALUES(VALUE_FIELD)
ID_XXX_TABLE NUMBER REFERENCES XXX_TABLE (ID_XXX_TABLE)
CHILD_TABLE (2,000,000 rows)
ID_CHILD NUMBER PRIMARY KEY
ID_PARENT NUMBER REFERENCES PARENT_TABLE(ID_PARENT) CASCADE DELETES
BLAH VARCHAR2(15)
BLAH_BLAH VARCHAR2(100)
VALUE_FIELD VARCHAR2(20) REFERENCES VALID_VALUES(VALUE_FIELD)
XXX_TABLE (100,000 rows)
ID_XXX_TABLE NUMBER PRIMARY KEY
FUBAR NUMBER
FOOBAR NUMBER
VALUE_FIELD VARCHAR2(20) REFERENCES VALID_VALUES(VALUE_FIELD)
VALID_VALUES (25 rows)
VALUE_FIELD VARCHAR2(20) PRIMARY KEY
GOOD_BAD_UGLY CHAR(1) CHECK(GOOD_BAD_UGLY IN ('G', 'B', 'U')
Run Code Online (Sandbox Code Playgroud)
在这种情况下,应创建以下索引:
PK_PARENT_TABLE ON PARENT_TABLE (ID_PARENT)
PARENT_TABLE_1 ON PARENT_TABLE (VALUE_FIELD)
PARENT_TABLE_2 ON PARENT_TABLE (ID_XXX_TABLE)
PK_CHILD_TABLE ON CHILD_TABLE (ID_CHILD)
CHILD_TABLE_1 ON CHILD_TABLE (ID_PARENT)
CHILD_TABLE_2 ON CHILD_TABLE (VALUE_FIELD)
PK_XXX_TABLE ON XXX_TABLE (ID_XXX_TABLE)
XXX_FIELD_1 ON XXX_TABLE (VALUE_FIELD)
PK_VALID_VALUES ON VALID_VALUES (VALUE_FIELD)
Run Code Online (Sandbox Code Playgroud)
为了解释为什么需要创建这些索引,让我们考虑当你想从这些表中删除一行时会发生什么:
PARENT_TABLE
DELETE FROM PARENT_TABLE WHERE ID_PARENT = 123
Run Code Online (Sandbox Code Playgroud)
执行此操作时,数据库需要查找引用要删除的行的每一行.只有一个表具有引用PARENT_TABLE的外键约束,即CHILD_TABLE.所以数据库必须执行相当于SELECT * FROM CHILD_TABLE WHERE ID_PARENT = 123.现在,这句话总是可以执行的-但如果CHILD_TABLE.ID_PARENT没有被索引它保证该计划将FULL TABLE SCAN与在CHILD_TABLE每一行都会有被读取.如果CHILD_TABLE有很多行,这将很慢.另一方面,如果CHILD_TABLE在ID_PARENT上有一个索引,它应该是一个直接索引查找,通常非常快.
VALID_VALUES
DELETE FROM VALID_VALUES WHERE VALUE_FIELD = 'ZORTNOBBLE'
Run Code Online (Sandbox Code Playgroud)
看起来很简单 - 只需从VALID_VALUES中删除一行,其中只有25行.应该快点吧?嗯...也许不是.有三个引用VALID_VALUES.VALUE_FIELD的外键约束 - 如果任何引用表缺少VALUE_FIELD上的索引,它将强制读取和检查该表中的每一行,以查看是否存在从VALID_VALUES中删除的值.这很可能是一个非常缓慢的操作.
因此,正如我所说,确保外键约束的BOTH SIDES上的表在每个外键中的所有字段上都有一个索引.您可能会发现这将极大地改善您的情况.
如果您可以编辑您的问题并包含所涉及的表的定义,包括所有外键约束以及这些表中存在的所有索引,则某人可能能够提供更具体的建议.
祝你好运.