我有一个包含数百万行的表。 我想根据last_updated列的值删除超过一周的所有数据。
这是我的两个查询,
方法1:
Delete from A where to_date(last_updated,''yyyy-mm-dd'')< sysdate-7;
方法2:
l_lastupdated varchar2(255) := to_char(sysdate-nvl(p_days,7),'YYYY-MM-DD');
insert into B(ID) select ID from A where LASTUPDATED < l_lastupdated;
delete from A where id in (select id from B);
考虑性能,安全性和锁定性的哪个更好?
答案 0 :(得分:1)
您存储的日期格式似乎适合进行正确的排序,因此您可以反过来将sysdate转换为字符串:
--this is false today
select * from dual where '2019-06-05' < to_char(sysdate-7, 'YYYY-MM-DD');
--this is true today
select * from dual where '2019-05-05' < to_char(sysdate-7, 'YYYY-MM-DD');
因此它将是:
Delete from A where last_updated < to_char(sysdate-7, ''yyyy-mm-dd'');
具有使用默认索引(如果有)的好处。
它的缺点是依赖于可能会更改的String / Varchar顺序,即北NLS发生了更改(如果我没记错的话),因此在任何情况下,您都应该在...之前进行一些测试...
从长远来看,您应该强制将列更改为适当的日期数据类型,但我想这对您不正确的了解;)
答案 1 :(得分:0)
如果您要删除表中的大多数行,我建议您采用另一种方法,即:
create <new table name> as
select *
from <old table name>
where <predicates for the data you want to keep>;
然后
drop table <old table name>;
最后,您可以将新表重命名为旧表。
您始终可以对新表进行分区(即,使用包含分区子句的单独语句创建新表,然后从旧表中插入一个作为选择插入新表中的内容)。
这样,当您需要删除行时,只需删除相关分区即可。
答案 2 :(得分:0)
假设删除操作删除了很大一部分数据和数百万行,请采用以下三种方法:
create table tmp
Delete from A where to_date(last_updated,''yyyy-mm-dd'')< sysdate-7;
drop table a;
rename tmp to a;
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:2345591157689
很显然,您需要复制所有索引,授权等。但是在线重新定义可以帮助完成此https://oracle-base.com/articles/11g/online-table-redefinition-enhancements-11gr1
到达12.2时,还有另一个更简单的选择:过滤后的举动。
这是一个alter table移动操作,带有一个额外的子句,指出要保留的行:
create table t (
c1 int
);
insert into t values ( 1 );
insert into t values ( 2 );
commit;
alter table t
move including rows where c1 > 1;
select * from t;
C1
2
当您等待升级到12.2+时,如果由于某种原因不想使用create-as-select方法,则方法1更好:
*语句级别的一致性意味着您在运行流程时可能会得到不同的结果。假设另一个会话尝试更新您的流程将要删除的旧行。
仅删除,更新将被阻止,直到删除完成。此时行已消失,因此更新不执行任何操作。
如果您先执行插入操作,则另一个会话可以在插入操作完成之前更新并提交该行。因此更新“成功”。但是删除后将其删除!可能导致一些不满意的客户...