web-dev-qa-db-fra.com

Différence entre FETCH / FOR pour boucler un CURSOR en PL / SQL

Je sais que la récupération d'un curseur me donnera accès à des variables comme% ROWCOUNT,% ROWTYPE,% FOUND,% NOTFOUND,% ISOPEN

... mais je me demandais s'il y avait d'autres raisons d'utiliser

Ouvrir - Récupérer - Fermer les instructions pour boucler un curseur

plutôt que

Bouclez le curseur avec un cycle FOR ... (À mon avis c'est mieux car c'est simple)

Qu'est-ce que tu penses?

14
Jimmy

Du point de vue des performances, la différence est beaucoup plus compliquée que ce que le conseil de Tim Hall auquel OMG Ponies a lié impliquerait. Je pense que cette astuce est une introduction à une section plus large qui a été extraite pour le Web - je m'attends à ce que Tim continue à faire la plupart sinon la totalité de ces points dans le livre. De plus, toute cette discussion dépend de la version d'Oracle que vous utilisez. Je pense que c'est correct pour 10.2, 11.1 et 11.2, mais il y a certainement des différences si vous commencez à revenir à des versions plus anciennes.

L'exemple particulier de la pointe, tout d'abord, est plutôt irréaliste. Je n'ai jamais vu personne coder une extraction sur une seule ligne en utilisant un curseur explicite plutôt qu'un SELECT INTO. Le fait que SELECT INTO soit plus efficace n'a donc qu'une importance pratique très limitée. Si nous discutons de boucles, les performances qui nous intéressent sont le coût de la récupération de nombreuses lignes. Et c'est là que la complexité commence à entrer.

Oracle a introduit la possibilité de faire une COLLECTE EN VRAC de données à partir d'un curseur dans une collection PL/SQL dans 10.1. C'est un moyen beaucoup plus efficace d'obtenir des données du moteur SQL vers la collection PL/SQL car il vous permet de minimiser les changements de contexte en récupérant plusieurs lignes à la fois. Et les opérations ultérieures sur ces collections sont plus efficaces car votre code peut rester dans le moteur PL/SQL.

Cependant, pour tirer le meilleur parti de la syntaxe BULK COLLECT, vous devez généralement utiliser des curseurs explicites, car de cette façon, vous pouvez remplir une collection PL/SQL, puis utiliser la syntaxe FORALL pour réécrire les données dans la base de données (sur le l'hypothèse raisonnable que si vous récupérez un tas de données dans un curseur, il y a une forte probabilité que vous fassiez une sorte de manipulation et sauvegardiez les données manipulées quelque part). Si vous utilisez un curseur implicite dans une boucle FOR, comme OMG Ponies le souligne correctement, Oracle effectuera une COLLECTE EN VRAC en arrière-plan pour rendre la récupération des données moins coûteuse. Mais votre code effectuera des insertions et des mises à jour ligne par ligne plus lentement car les données ne sont pas dans une collection. Les curseurs explicites offrent également la possibilité de définir explicitement la LIMITE, ce qui peut améliorer les performances par rapport à la valeur par défaut de 100 pour un curseur implicite dans une boucle FOR.

En général, en supposant que vous utilisez la version 10.2 ou supérieure et que votre code récupère des données et les réécrit dans la base de données,

Le plus rapide

  1. Curseurs explicites faisant un BULK COLLECT dans une collection locale (avec une LIMIT appropriée) et utilisant FORALL pour réécrire dans la base de données.
  2. Les curseurs implicites effectuant une COLLECTE EN VRAC pour vous dans les coulisses avec des écritures sur une seule ligne dans la base de données.
  3. Curseurs explicites qui ne font pas de BULK COLLECT et ne profitent pas des collections PL/SQL.

Plus lent

D'un autre côté, l'utilisation de curseurs implicites vous offre un certain avantage d'utiliser des opérations en bloc pour très peu du coût initial de refactorisation de l'ancien code ou d'apprentissage de la nouvelle fonctionnalité. Si la plupart de votre développement PL/SQL est effectué par des développeurs dont le langage principal est autre chose ou qui ne suivent pas nécessairement les nouvelles fonctionnalités du langage, les boucles FOR seront plus faciles à comprendre et à maintenir que le code de curseur explicite qui utilisait tous les nouvelle fonctionnalité BULK COLLECT. Et quand Oracle introduira de nouvelles optimisations à l'avenir, il est beaucoup plus probable que le code de curseur implicite obtienne automatiquement l'avantage tandis que le code explicite peut nécessiter une retouche manuelle.

Bien sûr, au moment où vous dépannez les performances au point où vous vous souciez vraiment de la rapidité avec laquelle différentes variantes de votre code de boucle peuvent être, vous êtes souvent au point où vous voudrez envisager de déplacer plus de logique en SQL pur et abandonner le code en boucle entièrement.

27
Justin Cave

OPEN/FETCH/CLOSE est appelé syntaxe de curseur explicite; cette dernière est appelée syntaxe de curseur implicite.

Une différence clé que vous avez déjà remarquée est que vous ne pouvez pas utiliser% FOUND /% NOTFOUND/etc dans les curseurs implicites ... Une autre chose à savoir est que les curseurs implicites sont plus rapides que ceux explicites - ils lisent à l'avance (~ 100 enregistrements?) En plus de ne pas supporter la logique explicite.

Information additionnelle:

7
OMG Ponies

Corrigez-moi si je me trompe, mais je pense que les deux ont une fonctionnalité intéressante que l'autre n'a pas.

Avec la boucle for, vous pouvez faire comme ceci:

for i in (select * from dual)
  dbms_output.put_line('ffffuuu');
end loop;

Et avec open .. fetch, vous pouvez faire comme ceci:

declare
  cur sys_refcursor;
  tmp dual.dummy%type;
begin
  open cur for 'select dummy from dual';
  loop
    fetch cur into tmp;
    exit when cur%notfound;
    dbms_output.put_line('ffffuuu');
  end loop;
  close cur;
end;

Donc avec open fetch vous pouvez utiliser des curseurs dynamiques mais avec for loop vous pouvez définir un curseur normal sans déclaration.

3
Jokke Heikkilä

Je ne connais pas de différences cruciales dans ces deux réalisations à part une: for ... loop ferme implicitement le curseur une fois la boucle terminée et si open ... fetch ... close syntaxe vous préférez fermer le curseur vous-même (juste dans le bon sens) - pensant que ce n'est pas une nécessité: Oracle fermera automatiquement le curseur en dehors de la portée de visibilité. Vous ne pouvez pas non plus utiliser %FOUND et %NOTFOUND dans for ... loop curseurs.

Quant à moi, je trouve le for ... loop réalisation beaucoup plus facile à lire et à supporter.

3
andr