This seems like a complicated issue. A few notes:
1) Your solution is really quite expensive in terms of DB resources. Deletes will put big strain on your undo and redo. Frequent commits do not help either (therefore,
you should at least try to make your batch size as big as possible).
However, the fastest way would be to
create as select a new table from the old one, selecting only rows which you want to keep. Then drop the old table and rename the new one to the original name, and recreate all constraints the old table had. Do one table at a time to minimize space utilization. The temp table Jayesh suggested saves you the work with recreating table constraints, but the data you need to keep after the delete will be copied twice. Moreover,
create as select can save lots of undo/redo space (depending on whether your DB is mirrored to a standby).
2) Check carefully for differences between test and production environments. Is the schema identical? Aren't some indexes/constrains unusable or invalid in prod/test? Is the volume/structure of actual data comparable? Is DB utilization the same? Aren't there any other processing active on prod which are not on test?
Some issues can even arise because of data copied by imp/exp from prod to test are stored in a different physical arrangements on the disks.
3) Make sure you've got valid and usable indexes on all affected foreign keys. This is very important, especially if you perform delete cascade. Deleting from a parent table which is referred by unindexed foreign keys causes locking of the whole child table, that may interfere with other processes taking place.
4) Delete cascade performs worse than doing it manually. I've done some experiments in the past and it seems that cascade delete can do perhaps twice as much work compared to deleting the records manually. But compared to the first point this is much less significant.
5) Enabling constraints can indeed take a lot of time needed to validate them. You can
enable novalidate a constraint, which happens immediately, but you really should read about possible ramifications in the docs, I'm no expert on this. You might need to add
rely to the command. And you'll certainly need to check twice that the constraint you've chosen not to validate is not violated - Oracle won't check, obviously. You can also validate a constraint that was created as
novalidate later, I believe this is an online operation.