1.我有一个表t_orders包含40mn条记录。
1.该表每天在trans_dt上进行分区。
1.我想根据p_code='OTC'删除大约2500万条记录
1.我想用下面的方法,这似乎更快。有没有什么方法可以像下面这样基于多个分区进行删除?例如使用2分区(SYS_P20209,SYS_P20345)。在使用一个分区的情况下,它工作得很好。
ALTER SESSION ENABLE PARALLEL DML;
DELETE t_orders PARTITION(SYS_P20209,SYS_P20345) WHERE p_code = 'OTC';
COMMIT;
提前谢谢你,喀什
1条答案
按热度按时间kmbjn2e31#
你想删除4000万中的2500万,或者整个表的62%?你不想使用
DELETE
,因为撤销和重做的数量将是巨大的,如果它失败或你中止它,你可能会结束一个非常长的回滚时间。处理此问题的正确方法是重新创建段。您可以通过以下几种方式执行此操作:1.使用
CREATE TABLE AS SELECT
(CTAS)创建一个新表,其中只包含要保留的数据。CTAS允许分区语法,因此您可以在创建表时对其进行分区,而不是预先创建表或稍后更改表。然后重命名旧表,将新表重命名为旧表,应用任何赠款、索引等。旧table上的东西你就完了。这是不使用脚本的最有效的方法。1.使用
CREATE TABLE AS SELECT
创建一个临时表,其中只包含要保留的数据。截断主表,启用并行dml并将临时表中的append插入回主表。这具有移动数据两次的缺点,但避免了必须重新定义依赖对象/赠款等。1.由于它是分区的,您可以通过分区编写PL/SQL循环(查询
all_tab_partitions
以获得分区名称),并使用扩展分区命名语法逐个CTAS每个分区到临时表,只移动您想要保留的数据。使用扩展分区语法时,一次只能处理一个分区。然后使用ALTER TABLE EXCHANGE PARTITION
将旧分区与临时表交换。完成后重建索引。这与#1 plus一样高效,避免了必须重新应用赠款和重新定义索引等。但当然只对分区表起作用。1.最后,如果你绝对必须做一个真实的的
DELETE
(同样,不推荐),这里有一些选择:禁用索引和触发器。启用并行dml和 hint(如果没有提示,启用并行dml可能不会执行任何操作):
DELETE /*+ parallel(16) */ FROM t_orders...
。完成后,重建索引并重新启用触发器。4 b.通过分区名编写PL/SQL循环,并使用扩展的分区命名语法执行#4a中提示的并行dml删除,但仅针对一个分区。提交每个循环迭代。这可确保所有并行线程按数据块范围均匀分布工作负载,而不是Oracle可能选择分区分布,因为分区分布可能存在偏差并导致并行化效率降低。它还保持回滚时间和空间需求的撤消下降到一个更合理的水平,因为你只做一个分区的时间。但是如果失败了,你需要知道你在哪里停止了,因为这是在提交的块中而不是在一个事务中执行操作。示例: