CREATE TABLE NEW_TABLE NOLOGGING PARALLEL 4 AS SELECT OLD_TABLE.* FROM OLD_TABLE WHERE (condiction) TRUNCATE TABLE OLD_TABLE; INSERT INTO OLD_TABLE SELECT * FROM NEW_TABLE;
I need to delete 5.5 million rows from an Oracle table that has about 100 million rows. I have all the IDs of the rows I need to delete in a temporary table. If it were a just a few thousand rows, I'd do this: sql
DELETE FROM table_name WHERE id IN (SELECT id FROM temp_table); COMMIT;
Is there anything I need to be aware of, and/or do differently, because it's 5.5 million rows? I thought about doing a loop, something like this: app
DECLARE vCT NUMBER(38) := 0; BEGIN FOR t IN (SELECT id FROM temp_table) LOOP DELETE FROM table_name WHERE id = t.id; vCT := vCT + 1; IF MOD(vCT,200000) = 0 THEN COMMIT; END IF; END LOOP; COMMIT; END;
First of all - is this doing what I think it is - batching commits of 200,000 at a time? Assuming it is, I'm still not sure if it's better to generate 5.5 million SQL statements, and commit in batches of 200,000, or to have one SQL statement and commit all at once. ide
Ideas? Best practices? oop
EDIT: I ran the first option, the single delete statement, and it only took 2 hours to complete in development. Based on that, it's queued to be run in production. Thanks for your input! this
A:The first approach is better, because you give the query optimizer a clear picture of what you are trying to do, instead of trying to hide it. The database engine might take a different approach to deleting 5.5m (or 5.5% of the table) internally than to deleting 200k (or 0.2%). spa
Here is also an article about massive DELETE in Oracle which you might want to read. code
The fastest way is to create a new one with CREATE TABLE AS SELECT using NOLOGGING option. I mean: server
ALTER TABLE table_to_delete RENAME TO tmp; CREATE TABLE table_to_delete NOLOGGING AS SELECT .... ;
Of course you have to recreate constraints with no validate, indexes with nologging, grants, ... but is very very fast. get
If you have the trouble in production, you can do the following: input
ALTER TABLE table_to_delete RENAME to tmp; CREATE VIEW table_to_delete AS SELECT * FROM tmp; -- Until there can be instantly CREATE TABLE new_table NOLOGGING AS SELECT .... FROM tmp WHERE ...; <create indexes with nologging> <create constraints with novalidate> <create other things...> -- From here ... DROP VIEW table_to_delete; ALTER TABLE new_table RENAME TO table_to_delete; -- To here, also instantly
You have take care of:
Another option better than create milions of inserts is:
-- Create table with ids DELETE FROM table_to_delete WHERE ID in (SELECT ID FROM table_with_ids WHERE ROWNUM < 100000); DELETE FROM table_with_ids WHERE ROWNUM < 100000; COMMIT; -- Run this 50 times ;-)
不少時候,因爲不能中止server,只能採起這種方法,注意要commit,要不回滾太大。
The PLSQL choice is not advisable because can create the Snapshot too old message due that you are commiting (and closing the transaction) with an opened cursor (the looped one) you want to continue using it. Oracle allows it but it's not a good practice.
UPDATE: Why I can ensure the last PLSQL block is going to work? Because I supose that: