10
votes

Comment optimiser une mise à jour SQL qui fonctionne sur une table Oracle avec des rangées de 700 m

UPDATE [TABLE] SET [FIELD]=0 WHERE [FIELD] IS NULL
[TABLE] is an Oracle database table with more than 700 million rows. I cancelled the SQL execution after it had been running for 6 hours.Is there any SQL hint that could improve performance? Or any other solution to speed that up?EDIT: This query will be run once and then never again.

1 commentaires

Assurez-vous que vous n'ajoutez pas de contrainte nulle après la mise à jour afin que vous ne puissiez jamais faire cela à nouveau.


5 Réponses :


0
votes

Vous pouvez obtenir le même résultat sans mettre à jour en utilisant une table d'alimentation pour définir la valeur "Par défaut" sur 0.


5 commentaires

Cela serait-il plus rapide cependant?


Ce serait plus rapide car il ne met pas à jour les données de la table en aucun cas, la définition de la table


OK, mais dans ce cas, je dois mettre à jour les lignes existantes et non seulement la définition de la table.


Non, vous racontez Oracle de transmettre la valeur par défaut zéro au lieu d'une valeur null chaque fois qu'elle rencontre une null - tout cela a lieu sur le traitement SELECT, il n'y a pas de mise à jour sur la table réelle.


-1 Désolé, cela ne fonctionne pas. Changer la valeur par défaut ne met pas à jour les lignes existantes. (Cette astuce "Mise à jour bon marché" ne fonctionne que si vous ajoutez une nouvelle colonne à la fois une contrainte par défaut et une contrainte NON NULL dans une seule opération - dans Oracle 11G.)



11
votes

Tout d'abord, c'est une requête unique ou s'agit-il d'une requête récurrente? Si vous devez seulement le faire une fois que vous voudrez peut-être examiner la requête en mode parallèle. Vous devrez scanner toutes les lignes de toute façon, vous pourriez diviser la charge de travail vous-même avec des gammes de railid (parallélisme de soi-même de soi-même) ou utilisez des fonctionnalités intégrées Oracle.

supposant que vous souhaitez l'exécuter fréquemment et que vous souhaitez optimiser Cette requête, le nombre de lignes avec la colonne lorsque NULL sera éventuellement petite par rapport au nombre total de lignes. Dans ce cas, un index pourrait accélérer les choses. Oracle ne indice pas les lignes qui ont toutes les colonnes indexées telles que NULL, donc un indice sur le champ n'utilisera pas par votre requête (puisque vous voulez trouver toutes les lignes où champ est null).

soit:

  • créer un index sur (champ, 0) , le 0 agira comme une pseudocolune non nulle et toutes les lignes seront indexées sur la table.
  • créer un index basé sur la fonction sur (cas lorsque le champ est null, alors 1 extrémité) , cela n'indiquera que les lignes qui sont des nuls (l'index serait donc très compact). Dans ce cas, vous devriez réécrire votre requête:

    Mettre à jour [Table] Définir [champ] = 0 où (le cas où le champ est null, 1 extrémité) = 1

    EDIT:

    Comme il s'agit d'un scénario unique, vous pouvez utiliser le parallèle indice: xxx < / pré>


2 commentaires

Bonjour Vincent, il s'agit d'une requête unique. Mais merci de couvrant les deux scénarios (une requête unique / requête récurrente) dans votre réponse.


Nice utilisation de l'exemple de plan d'explication



3
votes

Vincent a déjà répondu parfaitement à votre question, mais je suis curieux de "pourquoi" derrière cette action. Pourquoi mettez-vous la mise à jour de tous les NULL à 0?

Cordialement, Rob.


3 commentaires

Bonne question, rob. C'est parce que les nulls ne sont pas suivis dans des index normaux.


Dans ce cas, faire une mise à jour et changer la sémantique de vos données semble assez drastique. Vous pouvez créer un index basé sur la fonction ou un sur ([champ] régulier, 1).


Oui, c'est une approche que nous envisageons. Merci



1
votes

Quelques suggestions:

  1. dépose des index contenant du champ avant d'exécuter votre relevé de mise à jour, puis de les ajouter plus tard.

  2. Écrivez une procédure PL / SQL pour le faire qui commet chaque 1000 ou 10000 rangées.

    J'espère que cela aide.


0 commentaires

5
votes

sont d'autres utilisateurs mettent à jour les mêmes lignes de la table en même temps?

Si tel est le cas, vous pouvez frapper beaucoup de problèmes de concurrence (attendant des serrures) et cela vaut la peine de la rompre en transactions plus petites.

DECLARE
  v_cnt number := 1;
BEGIN
 WHILE v_cnt > 0 LOOP
   UPDATE [TABLE] SET [FIELD]=0 WHERE [FIELD] IS NULL AND ROWNUM < 50000;
   v_cnt := SQL%ROWCOUNT;
   COMMIT;
 END LOOP;
END;
/


0 commentaires