3 votes

PL/SQL - vérifier les fuites de mémoire ?

J'ai un code PL/SQL qui pourrait présenter une fuite de mémoire. Chaque fois que je l'exécute, il semble s'exécuter de plus en plus lentement par rapport à la fois précédente, même si je diminue la taille de l'entrée. Le code dont je me méfie consiste à remplir un tableau à partir d'un curseur en utilisant bulk-collect, quelque chose comme ceci

    open c_myCursor(in_key);
         fetch c_myCursor bulk collect into io_Array; /*io_array is a parameter, declared as in out nocopy */
    close c_myCursor;

Je ne sais pas comment vérifier ce qui cause ce ralentissement. Je sais qu'il existe des tables dans Oracle qui suivent ce type d'utilisation de la mémoire, mais je ne suis pas sûr qu'il soit possible de consulter ces tables et de trouver quelque chose d'utile sur ce que fait mon code.

J'ai également essayé de me déconnecter de la session et de me reconnecter après environ 10-15 minutes, mais cela reste très lent.

La version d'Oracle est la 10.2


Il s'avère donc qu'il y a était d'autres activités de la base de données. L'administrateur de la base de données a décidé d'exécuter de gros travaux d'insertion et de mise à jour à peu près au moment où j'ai commencé à modifier et à tester le code. J'ai soupçonné mon code d'être la cause principale parce que je n'avais pas été informé de l'exécution des autres tâches (et je n'ai entendu parler de cette autre tâche qu'après qu'elle ait complètement gelé la base et que tous les autres développeurs se soient énervés). C'est probablement la raison pour laquelle mon code devenait de plus en plus lent.

Existe-t-il un moyen de le découvrir de manière programmatique, par exemple en interrogeant une session qui insère/modifie de nombreuses données, au cas où le DBA oublierait de me le dire la prochaine fois qu'il le fera ?

2voto

jonearles Points 11924

V$sessmetric est un moyen rapide de voir quelles ressources chaque session utilise - cpu, physical_reads, logical_reads, pga_memory, etc.

2voto

Gary Myers Points 24819

"J'ai essayé de me déconnecter de la session et de me reconnecter après environ 10-15 minutes, mais c'est toujours très lent.

En supposant que vous utilisiez une connexion dédiée conventionnelle sur une plate-forme *nix, cela exclut pratiquement toute fuite de mémoire. Lorsque vous établissez une nouvelle connexion à une base de données, oracle crée un nouveau processus et toute la mémoire PGA appartient à ce processus et est libérée (par le système d'exploitation) lorsque la session est déconnectée et le processus terminé.

Si vous utilisez des connexions de serveur partagées, la session utilise la mémoire appartenant à la fois au processus et à la mémoire partagée. Cette situation est probablement plus vulnérable à un problème de fuite de mémoire.

Windows ne fonctionne pas tout à fait de la même manière, car il ne crée pas un processus distinct pour chaque session, mais dispose plutôt d'un fil d'exécution distinct sous un processus Oracle unique. Là encore, je soupçonne que cela serait plus vulnérable à une fuite de mémoire.

En général, je chercherais d'abord d'autres problèmes, et je commencerais probablement par la requête sous-jacente à c_myCursor. Peut-être doit-il lire d'autres anciennes données pour atteindre les nouvelles ?

0voto

Gábor Lipták Points 3745

http://www.dba-oracle.com/t_plsql_dbms_profiler.htm décrit DBMS_PROFILER. Je suppose que les parties les plus lentes de votre code peuvent être liées à des fuites de mémoire. Quoi qu'il en soit, si vous revenez au problème initial, à savoir que le système est de plus en plus lent, la première chose à faire est de déterminer ce qui est lent, puis de supposer qu'il y a une fuite de mémoire.

Il semble que vous ne fassiez pas de commit entre les exécutions, et que le redo log soit de plus en plus grand. C'est probablement la raison pour laquelle la base de données doit assurer la cohérence en lecture.

Vous pouvez également consulter la console de gestion de l'entreprise. Quelle version utilisez-vous ? Je n'utilise jamais la version XE pour le développement, car, pour autant que je sache, la version professionnelle peut être utilisée à des fins de développement. La console de gestion d'entreprise vous donne même des suggestions. Elle peut peut-être vous dire quelque chose d'intelligent à propos de votre problème PLSQL.

0voto

Leo Takacs Points 1

Si votre requête renvoie beaucoup les données de votre collection peuvent devenir extrêmement volumineuses, par exemple 10 000 000 d'enregistrements - c'est alors que l'utilisation de la mémoire devient suspecte.

Vous pouvez le vérifier en enregistrant la taille de la collection dans laquelle vous effectuez la collecte en vrac. Si elle est supérieure à 10 000 (il s'agit d'une estimation approximative, qui dépend bien sûr des données), vous pouvez envisager de la diviser et de travailler avec des parties de données, quelque chose comme ça :

declare
  cursor cCur is select smth from your_table;
  --
  type TCur is table of cCur%rowtype index by pls_integer;
  --
  fTbl TCur;
begin
  open cCur;
  loop
    fTbl.delete;
    fetch cCur bulk collect into fTbl limit 10000;
    exit when cCur%notfound;

    for i in 1 .. fTbl.count loop
      --do your wok here
    end loop;
  end loop;
  close cCur;
end;

Puisque vous avez dit que la table est déclarée comme in out nocopy, je comprends que vous ne puissiez pas réécrire directement la logique comme cela, mais considérez simplement la méthodologie, peut-être que cela peut vous aider.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X