La suppression d'un grand nombre de données dans Oracle
Je ne suis pas une base de données de la personne, exactement, et la plupart de mes db de travail a été avec MySQL, donc pardonnez-moi si quelque chose dans cette question est incroyablement naïf.
J'ai besoin de supprimer 5,5 millions de lignes d'une table Oracle qui a près de 100 millions de lignes. J'ai tous les Id des lignes j'ai besoin de supprimer dans une table temporaire. Si c'était juste quelques milliers de lignes, je ferais ceci:
DELETE FROM table_name WHERE id IN (SELECT id FROM temp_table);
COMMIT;
Est-il quelque chose j'ai besoin d'être conscient de, et/ou faire différemment, parce que c'est de 5,5 millions de lignes? J'ai pensé à faire une boucle, quelque chose comme ceci:
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;
Tout d'abord, est - ce faire ce que je pense qu'il est - le dosage s'engage de 200 000 à un moment? En supposant qu'il est, je ne sais pas encore si c'est mieux pour générer de 5,5 millions de SQL, et de s'engager dans des lots de 200 000, ou d'avoir une instruction SQL et de s'engager à la fois.
Idées? Les meilleures pratiques?
MODIFIER: j'ai couru la première option, la seule instruction delete, et il n'a fallu que 2 heures pour se terminer en développement. Sur cette base, il est en attente d'être exécutés en production.
OriginalL'auteur Sarah Mei | 2009-03-13
Vous devez vous connecter pour publier un commentaire.
La première approche est la meilleure, parce que vous donnez l'optimiseur de requête une image claire de ce que vous essayez de faire, au lieu d'essayer de le cacher. Le moteur de base de données peut prendre une approche différente de la suppression de 5,5 m (soit 5,5% de la table) à l'interne qu'à l'effacement de 200k (soit 0,2%).
Voici aussi un l'article massif SUPPRIMER dans Oracle qui vous voudrez peut-être lire.
Mais ensuite, vous devez avoir un énorme annuler l'espace de match, ce qui est pourquoi certains d'entre nous forcé de faire la validation du lot
Si vous pouvez vous en sortir avec un grand succès, bien sûr, d'aller pour elle. Tho, il y a encore de nombreuses raisons de s'impliquer dans des lots, en fonction de la charge de travail et des ressources disponibles. Trop souvent, on peut voir chétif bases de données doté d'annuler fichiers de données autoextended à max, généralement juste à côté d'une aussi importante tablespace où une énorme piste de vérification vie n'est plus.
OriginalL'auteur Jiri Klouda
Le moyen le plus rapide est de créer un nouveau avec
CREATE TABLE AS SELECT
à l'aide deNOLOGGING
option. Je veux dire:Bien sûr, vous devez recréer les contraintes sans les valider, les indices avec nologging, subventions, ... mais c'est très très rapide.
Si vous avez de la difficulté dans la production, vous pouvez effectuer les opérations suivantes:
Vous devez prendre soin de:
NOLOGGING
signifie que minimale refaire sont générés. Si vous avez le rôle de DBA, exécuter unALTER SYSTEM CHECKPOINT
pour s'assurer qu'aucune perte de données si l'instance de crash.NOLOGGING
le tablespace être aussi dansNOLOGGING
.Une autre option de mieux que de créer des millions d'insertions est de:
Le PLSQL choix n'est pas conseillé parce que peut créer la Instantané trop vieux message à cause que vous êtes la validation (et la clôture de la transaction) avec un curseur ouvert (la boucle) vous souhaitez continuer à l'utiliser. Oracle permet à elle, mais c'est pas une bonne pratique.
Mise à JOUR: Pourquoi je ne peux garantir le dernier PLSQL bloc est d'aller travailler? Parce que je supose que:
Oui, exactement. Vous n'avez pas de temps d'arrêt?
Nous n', mais assez rarement - c'est arrivé une fois dans l'année, j'ai été ici. La politique est généralement que, pour exiger un temps d'arrêt, votre changement de meilleures ont PAS d'AUTRE ALTERNATIVE. 🙂
Comment savez-vous que 'SELECT ID from table_with_ids where ROWNUM < 100000' sélectionne le même id 'DELETE from table_with_ids where ROWNUM < 100000' va supprimer? Vous ne pouvez pas savoir que pour vous, pouvez-vous?
J'ai mis à jour la réponse.
OriginalL'auteur FerranB
Lors de l'exécution de massives suppressions dans
Oracle
, assurez-vous que vous n'êtes pas en cours d'exécution hors deUNDO SEGMENTS
.Lors de l'exécution de
DML
,Oracle
écrit d'abord tous les changements dans leREDO
journal (le vieux de données ainsi que les nouvelles données).Lorsque le
REDO
journal est rempli ou un délai d'attente se produit,Oracle
effectuelog synchronization
: il écritnew
des données dans les fichiers de données (dans votre cas, les marques de la forme de blocs libres), et les écritures anciennes données dans leUNDO
tablespace (afin qu'il reste visible pour les transactions simultanées jusqu'à ce que vouscommit
vos modifications).Lorsque vous validez vos modifications, de l'espace dans
UNDO
segments occupés par yuor transaction est libéré.Cela signifie que si vous supprimez
5M
lignes de données, vous aurez besoin d'avoir de l'espace pourall
ces lignes dans votreUNDO
segments, de sorte que les données peuvent être déplacées en premier (all at once
) et supprimé qu'après validation.Cela signifie également que les requêtes simultanées (le cas échéant) devront lire à partir de
REDO
journaux ouUNDO
segments lors de l'exécution d'analyses de la table. Ce n'est pas le moyen le plus rapide pour accéder à des données.Cela signifie également que si l'optimiseur de sélectionner
HASH JOIN
pour votre suppression de la requête (ce qui sera probablement le faire), et la table temporaire ne rentre pas dans leHASH_AREA_SIZE
(qui sera très probablement être le cas), alors la requête devraseveral
scanne sur la grande table, et de certaines parties de la table sera déjà déménagé dansREDO
ouUNDO
.Donné tous dit ci-dessus, vous feriez probablement mieux de supprimer des données dans
200,000
morceaux et valider les modifications entre les deux.Donc, vous, d'abord, se débarrasser des problèmes décrits ci-dessus et, d'autre part, d'optimiser votre
HASH_JOIN
, que vous aurez le même nombre de lectures, mais le lit eux-mêmes seront plus efficaces.Dans votre cas, cependant, je voudrais essayer de forcer l'optimiseur à utiliser
NESTED LOOPS
, que je pense qu'il sera plus rapide dans votre cas.Pour ce faire, assurez-vous que votre temp table possède une clé primaire sur
ID
, et de réécrire votre requête comme suit:Vous aurez besoin de la clé primaire sur
temp_table
pour cette requête au travail.Comparer avec les éléments suivants:
voir ce qui est plus rapide et s'en tenir à cela.
OriginalL'auteur Quassnoi
C'est mieux de tout faire à la fois, comme dans votre premier exemple. Mais je serais certainement aller dessus avec votre DBA première depuis mai, ils veulent récupérer les blocs que vous n'utilisez plus, après la purge. Aussi, il peut y avoir des préoccupations concernant les horaires qui ne sont normalement pas visibles à partir du point de vue utilisateur.
Oui. aussi sous-optimale.
Seulement essayer de récupérer les blocs si ces enregistrements ont été une partie d'une grande erreur. Si ces documents étaient des conditions normales de fonctionnement, laissez les blocs seul, vous aurez à les utiliser de nouveau par la suite.
OriginalL'auteur Jon Ericson
Si votre version d'origine de SQL prend un temps très long, certains simultanées Sql peut s'exécuter lentement qu'ils ont à utiliser la commande ANNULER pour reconstruire une version des données sans votre les modifications non validées.
Un compromis pourrait être quelque chose comme
Vous pouvez ajuster ROWNUM que nécessaire. Un petit ROWNUM moyens de plus en plus fréquentes s'engage et (probablement) une réduction de l'impact sur d'autres sessions en termes de devoir demander une annulation. Toutefois, selon les plans d'exécution, il peut y avoir d'autres incidences, et il prendra probablement plus de temps ensemble.
Techniquement, le "POUR" une partie de la boucle est inutile, car la SORTIE ce sera la fin de la boucle. Mais je suis paranoïaque à propos illimité boucles que c'est une douleur pour tuer la session si elles ne se coincent.
Intéressante approche hybride en tout cas. Merci pour la réponse.
le plus vous validez le plus probable que vous obtenez un ORA-01555.
Marque:Dans l'exemple, je ne suis pas tenue de tout les curseurs ouverts au cours de la commettre, alors ne pas en obtenir un ORA-01555 ici. Si il n'y a rien en dehors de la boucle, il y a un risque, mais ce serait la même s'il y a un commit ou un mille.
Sarah: Pas besoin de la variable de boucle (i) dans le numéro de rangée de la clause. C'est juste successives supprime des centaines de milliers de lignes à chaque fois jusqu'à ce qu'il n'y a plus de gauche à supprimer.
OriginalL'auteur Gary Myers
Je recommande l'exécution de cette comme un simple delete.
Sont là tout enfant tables de celui que vous êtes en train de supprimer à partir de? Si oui, assurez-vous que la clé étrangère dans ces tableaux est indexé. Sinon, vous risquez de faire un balayage complet de la table enfant pour chaque ligne vous supprimer ce qui pourrait rendre les choses très lent.
Vous souhaitez que certaines façons de vérifier le progrès de la supprimer, car il fonctionne. Voir Comment vérifier la base de données oracle pour des requêtes de longue durée?
Que d'autres personnes ont suggéré, si vous voulez tester le l'eau, vous pouvez mettre: rownum < 10000 sur la fin de votre requête.
OriginalL'auteur WW.
J'ai fait quelque chose de similaire dans le passé avec Oracle 7, où j'ai dû supprimer des millions de lignes de milliers de tables. Pour tous autour de la performance et surtout le grand supprime (millions de lignes de plus dans un tableau) ce script fonctionnait bien.
Vous aurez à modifier légèrement (ie: examiner les utilisateurs/mots de passe, ainsi que d'obtenir des rollback segments de droite). Aussi vous avez vraiment besoin d'en discuter avec votre DBA et l'exécuter dans un environnement de TEST en premier. Ayant dit tout cela, c'est assez facile. La fonction delete_sql() cherche un lot de rowids dans la table que vous spécifiez puis les supprime lot par lot. Par exemple;
L'exemple ci-dessus est la suppression de 500 enregistrements à la fois à partir de la table MSF170 basé sur une instruction sql.
Si vous avez besoin de supprimer des données à partir de plusieurs tables, il suffit d'inclure supplémentaires
exec delete_sql(...)
lignes dans le fichier de supprimer les tables.sqlOh, et n'oubliez pas de mettre un rollback segments de nouveau en ligne, il n'est pas dans le script.
Oh, et un dernier conseil. Ça va être lent et en fonction de la table peut prendre un certain temps d'arrêt. Les tests, le calendrier et le réglage sont votre meilleur ami ici.
OriginalL'auteur Mark Nold
Toutes les réponses ici sont très bien, juste une chose à ajouter: si vous souhaitez supprimer tous des enregistrements dans une table, et sont sûr vous n'aurez pas besoin de la restauration, alors vous voulez utiliser la truncate table de commande.
(Dans votre cas, vous ne voulait supprimer un sous-ensemble, mais pour quelqu'un qui rôde avec un problème similaire, j'ai pensé que je pourrais ajouter)
OriginalL'auteur Evan
Le moyen le plus facile pour moi, c'est:-
OriginalL'auteur sandeep