【发布时间】:2014-12-30 22:07:44
【问题描述】:
我有一张大表,其中有很多数据被分成多个分区。我想保留一些分区,但从表中删除其余数据。我尝试搜索类似的问题,但在 stackoverflow 中找不到。在 Oracle 中编写查询以实现相同的最佳方式是什么?
【问题讨论】:
-
您要删除记录但保留分区吗?或者也删除分区?
-
不,我只想删除记录但保留分区本身 - 谢谢
我有一张大表,其中有很多数据被分成多个分区。我想保留一些分区,但从表中删除其余数据。我尝试搜索类似的问题,但在 stackoverflow 中找不到。在 Oracle 中编写查询以实现相同的最佳方式是什么?
【问题讨论】:
从特定分区删除数据很容易:此语句清除 2012 年 2 月的所有数据:
delete from t23 partition (feb2012);
更快的方法是截断分区:
alter table t23 truncate partition feb2012;
这里有两个潜在的障碍:
另外,它是 DDL,所以没有回滚。
如果我们再也不想存储那个月的数据,我们可以删除分区:
alter table t23 drop partition feb2012;
当我们想要快速切换多个分区并且我们不喜欢所有类型时,就会出现问题。我们无法参数化分区名称,因为它是对象名称而不是变量(没有引号)。所以只留下动态 SQL。
由于您要删除大部分数据但保留截断分区的分区结构是最佳选择。请记住使任何完整性约束无效(并在之后恢复它们)。
declare
stmt varchar2(32767);
begin
for lrec in ( select partition_name
from user_tab_partitions
where table_name = 'T23'
and partition_name like '%2012'
)
loop
stmt := 'alter table t23 truncate partition '
|| lrec.partition_name
;
dbms_output.put_line(stmt);
execute immediate stmt;
end loop;
end;
/
您绝对应该首先运行循环并注释掉 execute immediate 调用,这样您就可以看到您的 WHERE 子句选择了哪些分区。显然,您有一个备份并且可以恢复您不想删除的数据。但进行恢复的最快方法是不需要。
然后运行此查询以查看您应该重建哪些分区:
select ip.index_name, ip.partition_name, ip.status
from user_indexes i
join user_ind_partitions ip
on ip.index_name = i.index_name
where i.table_name = 'T23'
and ip.status = 'UNUSABLE';
您可以以类似的方式自动执行重建语句。
" 我正在考虑将我需要的分区的数据复制到临时 表并截断原始表并从 temp 复制回数据 表到原表。 "
这是另一种做事方式。使用交换分区可能会很快。它也可能更慢。它还取决于诸如外键和索引之类的东西,以及 zapped 分区与保留分区的比率。如果性能很重要和/或您需要定期执行此操作,那么您应该对各种选项进行基准测试并查看最适合您的选项。
【讨论】:
DELETE 或DROP 你也可以TRUNCATE 分区。
update global indexes。使用此子句,您不会使索引无效!
从分区表中删除分区时必须非常小心。分区表通常用于大数据表,如果(且仅当)你在表上有一个全局索引,删除分区会使你的全局索引无效,你应该在一个大表中重建你的全局索引,这是灾难。
为了在这种情况下对表查询的副作用最小,我首先删除分区中的记录并将其设为空分区,然后使用
ALTER TABLE table_name DROP PARTITION partition_name UPDATE GLOBAL INDEXES;
删除空分区而不使我的全局索引无效。
【讨论】: