Je gère une application qui a une très grande base de données Oracle (près de 1 To de données avec plus de 500 millions de lignes dans une table). La base de données ne fait vraiment rien (pas de SProcs, pas de déclencheurs ou quoi que ce soit), c'est juste un magasin de données.
Chaque mois, nous devons purger les enregistrements des deux tableaux principaux. Les critères de purge varient et sont une combinaison de l'âge des lignes et de quelques champs d'état. Nous finissons généralement par purger entre 10 et 50 millions de lignes par mois (nous ajoutons environ 3 à 5 millions de lignes par semaine via les importations).
Actuellement, nous devons effectuer cette suppression par lots d'environ 50 000 lignes (par exemple, supprimer 50000, comit, supprimer 50000, valider, répéter). Si vous tentez de supprimer le lot entier en une seule fois, la base de données ne répond plus pendant environ une heure (en fonction du nombre de lignes). La suppression des lignes en lots comme celui-ci est très rude sur le système et nous devons généralement le faire "si le temps le permet" au cours d'une semaine; permettre au script de s'exécuter en continu peut entraîner une dégradation des performances inacceptable pour l'utilisateur.
Je pense que ce type de suppression par lots dégrade également les performances de l'index et a d'autres impacts qui finissent par dégrader les performances de la base de données. Il y a 34 index sur une seule table, et la taille des données d'index est en fait plus grande que les données elles-mêmes.
Voici le script utilisé par l'un de nos informaticiens pour effectuer cette purge:
BEGIN
LOOP
delete FROM tbl_raw
where dist_event_date < to_date('[date]','mm/dd/yyyy') and rownum < 50000;
exit when SQL%rowcount < 49999;
commit;
END LOOP;
commit;
END;
Cette base de données doit être en hausse de 99,99999% et nous n'avons qu'une fenêtre de maintenance de 2 jours une fois par an.
Je cherche une meilleure méthode pour supprimer ces enregistrements, mais je n'en ai pas encore trouvé. Aucune suggestion?
la source
Réponses:
La logique avec 'A' et 'B' peut être "cachée" derrière une colonne virtuelle sur laquelle vous pouvez faire le partitionnement:
la source
La solution classique est de partitionner vos tables, par exemple par mois ou par semaine. Si vous ne les avez jamais rencontrés auparavant, une table partitionnée est comme plusieurs tables structurées de manière identique avec une implicite
UNION
lors de la sélection, et Oracle stockera automatiquement une ligne dans la partition appropriée lors de son insertion en fonction des critères de partitionnement. Vous mentionnez les index - eh bien, chaque partition obtient également ses propres index partitionnés. C'est une opération très bon marché dans Oracle de supprimer une partition (c'est analogue à unTRUNCATE
en termes de charge, car c'est ce que vous faites vraiment - tronquer ou supprimer l'une de ces sous-tables invisibles). Ce sera une quantité importante de traitement à répartir «après coup», mais cela n'a aucun sens de pleurer sur le lait renversé - les avantages de le faire l'emportent jusqu'à présent sur les coûts. Chaque mois, vous diviseriez la partition supérieure pour créer une nouvelle partition pour les données du mois suivant (vous pouvez facilement automatiser cela avec aDBMS_JOB
).Et avec les partitions, vous pouvez également exploiter l' élimination parallèle des requêtes et des partitions , ce qui devrait rendre vos utilisateurs très heureux ...
la source
A
alorsDateA
supérieur à 3 ans, il est purgé. Si le statut estB
et date deDateB
plus de 10 ans, il est purgé. Si ma compréhension du partitionnement est correcte, alors le partitionnement ne serait pas utile dans une situation comme celle-ci (au moins en ce qui concerne la purge).Un aspect à considérer est la proportion des performances de suppression des index et celle de la table brute. Chaque enregistrement supprimé de la table nécessite la même suppression de la ligne de chaque index btree. Si vous avez plus de 30 index btree, je soupçonne que la plupart de votre temps est consacré à la maintenance des index.
Cela a un impact sur l'utilité du partitionnement. Disons que vous avez un index sur le nom. Un index Btree standard, tout en un segment, peut avoir à effectuer quatre sauts pour passer du bloc racine au bloc feuille et une cinquième lecture pour obtenir la ligne. Si cet index est partitionné en 50 segments et que vous n'avez pas la clé de partition dans le cadre de la requête, chacun de ces 50 segments devra être vérifié. Chaque segment sera plus petit, vous n'aurez donc peut-être qu'à effectuer 2 sauts, mais vous pourrez toujours finir par faire 100 lectures au lieu des 5 précédentes.
S'il s'agit d'index bitmap, les équations sont différentes. Vous n'utilisez probablement pas d'index pour identifier des lignes individuelles, mais plutôt des ensembles d'entre elles. Ainsi, plutôt qu'une requête utilisant 5 E / S pour renvoyer un seul enregistrement, elle utilisait 10 000 E / S. En tant que tel, la surcharge supplémentaire dans les partitions supplémentaires pour l'index n'aura pas d'importance.
la source
la suppression de 50 millions d'enregistrements par mois par lots de 50 000 n'est que 1 000 itérations. si vous supprimez 1 toutes les 30 minutes, cela devrait répondre à vos besoins. une tâche planifiée pour exécuter la requête que vous avez publiée mais supprimez la boucle afin qu'elle ne s'exécute qu'une seule fois ne devrait pas entraîner une dégradation sensible pour les utilisateurs. Nous faisons à peu près le même volume d'enregistrements dans notre usine de fabrication qui fonctionne à peu près 24h / 24 et 7j / 7 et qui répond à nos besoins. Nous l'étalons en fait un peu plus de 10 000 enregistrements toutes les 10 minutes, qui s'exécutent en environ 1 ou 2 secondes sur nos serveurs Oracle Unix.
la source
Si l'espace disque n'est pas limité, vous pouvez créer une copie "de travail" de la table, par exemple
my_table_new
, en utilisant CTAS (Create Table As Select) avec des critères qui omettraient les enregistrements à supprimer. Vous pouvez faire l'instruction create en parallèle et avec l'indicateur d'ajout pour la rendre rapide, puis créer tous vos index. Ensuite, une fois terminé, (et testé), renommez la table existante enmy_table_old
et renommez la table "work" enmy_table
. Une fois que vous êtes à l'aise avec toutdrop my_table_old purge
pour vous débarrasser de l'ancienne table. S'il y a un tas de restrictions de clés étrangères, jetez un œil audbms_redefinition
package PL / SQL . Il clonera vos index, contraintes, etc. lors de l'utilisation des options appropriées. Ceci est un résumé d'une suggestion de Tom Kyte de AskTomla célébrité. Après la première exécution, vous pouvez tout automatiser, et la table de création devrait aller beaucoup plus vite, et peut être effectuée lorsque le système est en marche, et le temps d'arrêt de l'application serait limité à moins d'une minute pour renommer les tables. L'utilisation de CTAS sera beaucoup plus rapide que plusieurs suppressions de lots. Cette approche peut être particulièrement utile si vous n'avez pas de licence de partitionnement.Exemple de CTAS, en conservant les lignes avec les données des 365 derniers jours et
flag_inactive = 'N'
:la source
lorsque vous supprimez une partition, vous laissez les index globaux inutilisables, qui doivent être reconstruits, la reconstruction des index globaux serait un gros problème, car si vous le faites en ligne, ce sera assez lent, sinon vous avez besoin de temps d'arrêt. dans les deux cas, ne peut pas répondre à l'exigence.
"Nous finissons généralement par purger entre 10 et 50 millions de lignes par mois"
je recommanderais d'utiliser la suppression de lot PL / SQL, plusieurs heures est ok je pense.
la source