2010-11-09 27 views
3

J'ai un code PL/SQL que je pense pourrait avoir une fuite de mémoire. Chaque fois que je l'exécute, il semble courir plus lentement et plus lentement que la fois précédente, même si maintenant je diminue la taille de l'entrée. Le code que je me méfie de se peuplait un tableau à partir d'un curseur à l'aide en vrac recueillir, quelque chose comme çaPL/SQL - vérifier les fuites de mémoire?

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 suis pas sûr de savoir comment vérifier pour voir ce qui cause ce ralentissement. Je sais qu'il existe des tables dans Oracle qui permettent de suivre ce type d'utilisation de la mémoire, mais je ne suis pas sûr qu'il soit possible de regarder ces tables et de trouver un moyen de revenir à quelque chose d'utile sur mon code.

En outre, j'ai essayé de déconnecter la session et de me reconnecter après environ 10-15 minutes, toujours très lent.

Oracle version est 10,2


Ainsi, il se là-bas était autre activité de base de données. Le DBA a décidé d'exécuter de gros travaux d'insertion et de mise à jour à peu près au même moment où j'ai commencé à modifier et à tester le code. Je soupçonnais que mon code était la cause première, car on ne m'avait pas parlé des autres travaux en cours (et j'ai seulement entendu parler de cet autre travail après avoir complètement gelé tout et tous les autres développeurs se sont énervés). C'était probablement la raison pour laquelle mon code devenait de plus en plus lent et lent.

Existe-t-il un moyen de trouver cela par programme, comme interroger une session en insérant/mettant à jour beaucoup de données, juste au cas où le DBA oublierait de me dire la prochaine fois qu'il le fera?

+4

est PL/SQL, même vulnérable à des fuites de mémoire? SQL est un langage de très haut niveau et ceux-ci n'ont généralement pas ce problème. –

Répondre

2

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

+0

Intéressant ... Existe-t-il un moyen de voir * quel * objet la session utilise? Dans ce cas, le problème était qu'une table était mise à jour par un autre processus. J'imagine que si c'était une table différente je n'aurais pas eu un tel problème. Y a-t-il une autre vue pour joindre ceci à voir les objets en question? ou même si je pouvais juste voir quelle déclaration était en cours d'exécution ce serait probablement suffisant. . – FrustratedWithFormsDesigner

+1

sélectionnez sessmetric v $ *, sql_text, sql_fulltext de v $ sessmetric jointure externe gauche (select * from v $ sql où users_executing> 0) queries_running sur v $ sessmetric.session_id = queries_running.parsing_schema_id; –

0

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 connectées à une fuite de mémoire. Quoi qu'il en soit, si vous revenez au problème d'origine, que cela devient de plus en plus lent, alors la première chose à faire est de voir ce qui est lent, puis de supposer que la fuite de mémoire.

Il semble que vous ne commettiez pas de commit entre les exécutions, et le journal de rétablissement est de plus en plus important. Probablement c'est la cause que DB doit fournir la cohérence de lecture.

Vous pouvez également consulter la console de gestion d'entreprise. Quelle version utilisez-vous? Ne jamais utiliser XE pour le développement, car 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. Peut-être qu'il peut vous dire quelque chose d'intelligent sur votre problème PLSQL.

+0

Le code en question ne commet aucun commit, mais il ne fait pas non plus d'insertions. Aucune mise à jour, aucune suppression. Le script PL/SQL qui appelle le code suspect * a * un commit. Je n'utilise pas XE. Je vais devoir regarder le profileur. Notre IDE est PL/SQL Developer (par Allround Automation), et je pense qu'il peut automatiquement faire du profilage sur les scripts et le code qu'ils appellent, mais je ne suis pas sûr que ce profil me permette de définir ce dont j'ai besoin. Je vais devoir regarder dedans. – FrustratedWithFormsDesigner

+0

... oh oui, j'ai suspecté ce code parce qu'il est l'un des quelques nouveaux éléments du paquet modifié, mais c'est le seul code qui fait n'importe quel retrievel de données ET c'est le seul code qui remplit un tableau. – FrustratedWithFormsDesigner

2

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

En supposant que vous utilisez une connexion dédiée conventionnelle sur une plate-forme * nix, cela éliminerait à peu près toute fuite de mémoire. Lorsque vous établissez une nouvelle connexion à une base de données, Oracle décodera un nouveau processus et toute la mémoire PGA appartiendra à ce processus et sera libérée (par le système d'exploitation) lorsque la session sera déconnectée et le processus terminé.

Si vous utilisez des connexions de serveur partagé, la session utilise la mémoire appartenant au processus mais également à la mémoire partagée. Ce serait probablement plus vulnérable à tout problème de fuite de mémoire.

Windows ne fonctionne pas de la même manière, car il ne génère pas de processus distinct pour chaque session, mais dispose d'un thread séparé sous un seul processus Oracle. Encore une fois, je soupçonne que ce serait plus vulnérable à une fuite de mémoire.

Je chercherais généralement d'autres problèmes d'abord, et commencerai probablement à la requête sous-jacente c_myCursor. Peut-être qu'il doit lire plus de données anciennes pour obtenir les nouvelles données?

+0

Workstation est Windows, le serveur est unix (pas sûr de la saveur). Je ne sais pas si ce sont des connexions partagées ou dédiées. Les données que 'c_myCursor' examine sont assez statiques, elles ne sont rafraîchies que par les serveurs principaux lorsque nous les demandons au DBA, et cela depuis longtemps. – FrustratedWithFormsDesigner

0

Si votre requête renvoie beaucoup de données votre collection peut se développer énormément, disons 10 000 000 d'enregistrements - ce qui peut être le point de l'utilisation de la mémoire suspecte.

Vous pouvez vérifier cela en indiquant la taille de la collection dans laquelle vous effectuez la collecte en masse. Si elle est plus grande que 10 000 (juste une estimation approximative, cela dépend des données bien sûr), vous pouvez envisager de diviser et de travailler avec des parties de données, SMTH comme ceci:

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 Je comprends que vous ne pouvez pas directement réécrire la logique de cette façon, mais juste considérer la méthodologie, peut-être que cela peut vous aider.