Question

Je gère une application qui a une très grande (près de 1 To de données avec plus de 500 millions de lignes dans une table) Fin arrière de la base de données Oracle. La base de données n'a pas vraiment rien (pas Sprocs, aucun déclencheur ou quoi que ce soit), il est juste un magasin de données.

Chaque mois nous sommes tenus de dossiers de purge de deux des principaux tableaux. Les critères pour la purge varie et est une combinaison de l'âge de la rangée et un couple de zones de statut. Nous terminons généralement jusqu'à la purge entre 10 et 50 millions de lignes par mois (nous ajoutons environ 3-5 millions de lignes par semaine par les importations).

À l'heure actuelle, nous devons le faire par lots de suppression d'environ 50 000 lignes (ie. Supprimer 50000, Comit, supprimer 50000, commit, répétition). Toute tentative de supprimer le lot entier en une seule fois fait la base de données ne répond pas de pendant environ une heure (en fonction du nombre de lignes). Suppression des lignes de lots comme celui-ci est très rude sur le système et nous avons généralement de le faire «comme le temps le permet » au cours d'une semaine; permettant l'exécution du script peut continuellement entraîner la dégradation de la performance qui est inacceptable pour l'utilisateur.

Je crois que ce genre de lot suppression dégrade également les performances de l'indice et a d'autres impacts qui finira par causer la performance de la base de données à se dégrader. 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 que l'un de nos personnes utilise pour faire 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 jusqu'à 99,99999% et nous avons seulement une fenêtre de maintenance de 2 jours une fois par an.

Je suis à la recherche d'une meilleure méthode pour supprimer ces enregistrements, mais je n'ai pas encore trouver. Toutes les suggestions?

Était-ce utile?

La solution

La logique avec 'A' et 'B' pourrait être "caché" derrière un virtuel colonne sur laquelle vous pourriez faire le partitionnement:

alter session set nls_date_format = 'yyyy-mm-dd';
drop   table tq84_partitioned_table;

create table tq84_partitioned_table (
  status varchar2(1)          not null check (status in ('A', 'B')),
  date_a          date        not null,
  date_b          date        not null,
  date_too_old    date as
                       (  case status
                                 when 'A' then add_months(date_a, -7*12)
                                 when 'B' then            date_b
                                 end
                        ) virtual,
  data            varchar2(100) 
)
partition   by range  (date_too_old) 
( 
  partition p_before_2000_10 values less than (date '2000-10-01'),
  partition p_before_2000_11 values less than (date '2000-11-01'),
  partition p_before_2000_12 values less than (date '2000-12-01'),
  --
  partition p_before_2001_01 values less than (date '2001-01-01'),
  partition p_before_2001_02 values less than (date '2001-02-01'),
  partition p_before_2001_03 values less than (date '2001-03-01'),
  partition p_before_2001_04 values less than (date '2001-04-01'),
  partition p_before_2001_05 values less than (date '2001-05-01'),
  partition p_before_2001_06 values less than (date '2001-06-01'),
  -- and so on and so forth..
  partition p_ values less than (maxvalue)
);

insert into tq84_partitioned_table (status, date_a, date_b, data) values 
('B', date '2008-04-14', date '2000-05-17', 
 'B and 2000-05-17 is older than 10 yrs, must be deleted');


insert into tq84_partitioned_table (status, date_a, date_b, data) values 
('B', date '1999-09-19', date '2004-02-12', 
 'B and 2004-02-12 is younger than 10 yrs, must be kept');


insert into tq84_partitioned_table (status, date_a, date_b, data) values 
('A', date '2000-06-16', date '2010-01-01', 
 'A and 2000-06-16 is older than 3 yrs, must be deleted');


insert into tq84_partitioned_table (status, date_a, date_b, data) values 
('A', date '2009-06-09', date '1999-08-28', 
 'A and 2009-06-09 is younger than 3 yrs, must be kept');

select * from tq84_partitioned_table order by date_too_old;

-- drop partitions older than 10 or 3 years, respectively:

alter table tq84_partitioned_table drop partition p_before_2000_10;
alter table tq84_partitioned_table drop partition p_before_2000_11;
alter table tq84_partitioned_table drop partition p2000_12;

select * from tq84_partitioned_table order by date_too_old;

Autres conseils

La solution classique est de vos tables, par exemple par mois ou par semaine. Si vous n'êtes pas venu à travers eux avant, une table partitionnée est comme plusieurs tableaux structurés de manière identique avec une UNION implicite lors de la sélection, et Oracle enregistre automatiquement une ligne dans la partition appropriée lors de son insertion sur la base des critères de partitionnement. Vous mentionnez index - bien chaque partition est trop ses propres index partitionnés. Il est une opération très pas cher dans Oracle pour déposer une partition (il est analogue à un TRUNCATE en termes de charge parce que c'est ce que vous faites vraiment - tronquer ou de faire tomber l'un de ces sous-tables invisibles). Ce sera une quantité de traitement significative à la partition « après le fait », mais il n'y a aucun sens à pleurer lait sur renversé - les avantages à le faire l'emportent largement sur les coûts. Chaque mois, vous divisez la partition supérieure pour créer une nouvelle partition pour les données du mois prochain (vous pouvez facilement automatiser ths avec DBMS_JOB).

Et avec des partitions vous pouvez également exploiter et suppression de partition , ce qui devrait rendre vos utilisateurs très heureux ...

Un aspect à considérer est la quantité du résultat de la performance de suppression des index et la quantité de la table brute. Chaque enregistrement supprimé de la table exige la même suppression de la ligne de tous les indices de btree. Si vous avez plus de 30 btree indices, je soupçonne que la plupart de votre temps est consacré à la maintenance des index.

Cela a un impact sur l'utilité du partage. Disons que vous avez un indice sur le nom. Un index standard Btree, le tout dans un segment, pourrait avoir à faire quatre sauts pour obtenir du bloc racine au bloc de feuilles et un cinquième lecture pour obtenir la ligne. Si cet indice est divisé en 50 segments et vous n'avez pas la clé de la partition dans le cadre de la requête, puis chacun de ces 50 segments devront être vérifiés. Chaque segment sera plus petit, de sorte que vous ne pouvez avoir à faire 2 sauts, mais vous pouvez toujours finir par faire 100 lectures plutôt que le 5 précédent.

Si elles sont des index bitmap, les équations sont différentes. Vous n'êtes probablement pas utiliser les index pour identifier les lignes individuelles, mais plutôt des ensembles d'entre eux. Ainsi, plutôt que d'une requête en utilisant 5 IOs pour retourner un seul enregistrement, il utilisait 10.000 IOs. A ce titre les frais généraux supplémentaires dans des partitions supplémentaires pour l'index ne sera pas question.

suppression de 50 millions d'enregistrements par mois en lots de 50 000 est seulement 1000 itérations. si vous supprimez 1 toutes les 30 minutes, il devrait répondre à vos besoins. une tâche planifiée pour exécuter la requête mais que vous avez affichée supprimer la boucle de sorte qu'il exécute une seule fois ne devrait pas entraîner une dégradation notable aux utilisateurs. Nous faisons sur le même volume d'enregistrements dans notre usine de fabrication qui fonctionne à peu près 24/7 et il répond à nos besoins. Nous diffusons réellement un peu plus de 10.000 dossiers toutes les 10 minutes, qui exécute à environ 1 ou 2 secondes fonctionnant sur nos serveurs unix Oracle.

Si l'espace disque est pas une prime, vous pourriez être en mesure de créer un « travail » copie de la table, par exemple my_table_new, en utilisant CTAS (Créer une table Comme Select) avec des critères qui omettent les dossiers à supprimer. Vous pouvez faire la déclaration créer en parallèle, et avec l'indice append pour le rendre rapide, puis construire tous vos index. Puis, une fois il a terminé, (et testé), renommer la table existante pour my_table_old et renommer la table « travail » à my_table. Une fois que vous êtes à l'aise avec tout drop my_table_old purge pour se débarrasser de l'ancienne table. S'il y a un tas de contraintes clés étrangères, jetez un oeil à la dbms_redefinition PL / package SQL . Il cloner vos index, etc., contraintes lorsque vous utilisez les options appropriées. Ceci est une sommation d'une suggestion par Tom Kyte de AskTom renommée. Après la première manche, vous pouvez automatiser tout, et créer la table devrait aller beaucoup plus vite, et peut être fait alors que le système est en place, et les temps d'arrêt d'application serait limitée à moins d'une minute pour faire le changement de nom des tables. L'utilisation CTAS sera beaucoup plus rapide que de faire plusieurs suppressions de traitement par lots. Cette approche peut être particulièrement utile si vous n'avez pas partitionnement sous licence.

Exemple ETG, en gardant les lignes avec des données à partir des 365 derniers jours et flag_inactive = 'N':

create /*+ append */ table my_table_new 
   tablespace data as
   select /*+ parallel */ * from my_table 
       where some_date >= sysdate -365 
       and flag_inactive = 'N';

-- test out my_table_new. then if all is well:

alter table my_table rename to my_table_old;
alter table my_table_new rename to my_table;
-- test some more
drop table my_table_old purge;

lors de la suppression d'une partition, vous laissez les indices mondiaux inutilisables, qui ont besoin de reconstruire, la reconstruction des indices mondiaux serait un gros problème, comme si vous le faites en ligne, il sera assez lent, sinon vous avez besoin temps d'arrêt. dans les deux cas, ne peut pas répondre à l'exigence.

"Nous finissent généralement purger entre 10 et 50 millions de lignes par mois"

Je voudrais recommandé d'utiliser lot PL / SQL supprimer, plusieurs heures est ok, je pense.

Licencié sous: CC-BY-SA avec attribution
Non affilié à dba.stackexchange
scroll top