2010-11-09 68 views
3

我有一些我认为可能会发生内存泄漏的PL/SQL代码。每次运行它时,它似乎都比之前的运行速度慢,速度慢,即使现在我正在减小输入大小。我是可疑的代码是从一个游标使用批量收集,像这样PL/SQL - 检查内存泄漏?

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; 

我不知道如何检查,看看是什么导致这种放缓填充的数组。我知道在Oracle中有一些表格跟踪这种内存使用情况,但我不确定是否可以查看这些表格并找到回到我的代码正在做的事情的有用信息。

此外,我试图注销会话,并在约10-15分钟后重新登录,仍然非常缓慢。

Oracle版本是10.2


因此,原来有其他数据库活动。几乎在我开始更改和测试代码的同时,DBA决定运行一些大的插入和更新作业。我怀疑我的代码是根本原因,因为我没有被告知其他工作正在运行(我完全冻结了所有事情,而其他所有的开发人员都感到恼火后,我只听说过这个其他工作)。这可能是我的代码越来越慢的原因。

有没有一种方法可以以编程方式找到它,比如查询插入/更新大量数据的会话,以防DBA忘记告诉我下次他这样做?

+4

是PL/SQL甚至容易受到内存泄漏? SQL是一种非常高级的语言,通常不会有这个问题。 – 2010-11-09 20:10:45

回答

2

V $ sessmetric是一个快速的方法,看看有什么资源,每个会话使用 - CPU,physical_reads,logical_reads,pga_memory等

+0

有趣的......有没有办法看到*会话使用什么*对象?在这种情况下,问题是一个表正在被另一个进程更新。我想如果这是一张不同的桌子,我不会有这样的问题。有没有另外一种观点来加入这个观察对象的问题?或者即使我可以看到正在执行的语句可能就足够了。 。 – FrustratedWithFormsDesigner 2010-11-12 21:42:55

+1

选择V $ sessmetric *,SQL_TEXT,从V $ sessmetric sql_fulltext 左外连接 (SELECT * FROM V $ SQL WHERE users_executing> 0)queries_running上V $ sessmetric.session_id = queries_running.parsing_schema_id; – 2010-11-13 00:11:04

0

http://www.dba-oracle.com/t_plsql_dbms_profiler.htm描述了DBMS_PROFILER。我想你的代码中最慢的部分可以连接到内存泄漏。无论如何,如果你回到原来的问题,它变得越来越慢,那么首先要做的是看看什么是缓慢的,然后假设内存泄漏。

听起来好像你在执行之间没有提交,重做日志越来越大。可能这是DB需要提供读一致性的原因。

您还可以检查企业管理控制台。你使用哪个版本?切勿使用XE进行开发,因为据我所知专业版可用于开发目的。企业管理控制台甚至会给你建议。也许它可以告诉你一些关于你的PLSQL问题的聪明之处。

+0

有问题的代码没有做任何提交,但它也没有做任何插入。没有更新,没有删除。调用可疑代码*的PL/SQL脚本*具有提交。我没有使用XE。我将不得不看看分析器。我们的IDE是PL/SQL Developer(由Allround Automation开发),我认为它可以自动对脚本和他们调用的代码进行分析,但我不确定它是否描述了我需要的内容。我得看看它。 – FrustratedWithFormsDesigner 2010-11-09 21:11:33

+0

...哦,是的,我怀疑这个代码是因为它是修改后的包中的一些新东西之一,但它是唯一能够执行任何数据检索的代码,并且它是填充数组的唯一代码。 – FrustratedWithFormsDesigner 2010-11-09 21:12:28

2

“我试着注销会话并在大约10-15分钟后重新登录,仍然非常慢。”

假设您在* nix平台上使用传统的专用连接,这几乎可以排除任何内存泄漏。当你建立一个新的数据库连接时,oracle会为它分出一个新的进程,所有的PGA内存都属于这个进程,当会话被断开并且进程终止时,它将被释放(由OS)。

如果您使用的是共享服务器连接,则会话将使用属于进程但共享内存的内存。这可能会更容易受到任何内存泄漏问题的影响。

Windows的工作方式并不完全相同,因为它不会为每个会话分开一个单独的进程,而是在单个Oracle进程下有一个单独的线程。再一次,我怀疑这会更容易发生内存泄漏。

我通常会首先查找其他问题,并可能从查询基础c_myCursor开始。也许它必须阅读更多旧数据才能获得最新数据?

+0

工作站是Windows,服务器是unix(不知道是哪一种)。我不知道他们是共享连接还是专用的。 'c_myCursor'正在查看的数据非常静态,只有在我们从DBA请求它时才从主服务器刷新,并且一段时间没有。 – FrustratedWithFormsDesigner 2010-11-09 22:13:37

0

如果您的查询返回非常多数据您的集合可能会非常大,比如说10 000 000条记录 - 这可能是可疑内存使用的一点。

您可以通过记录您批量收集到的集合的大小来进行检查。如果是较大的是10 000(只是一个粗略的估计,这取决于课程的数据),你可以考虑拆分,并与数据的部分工作,水木清华这样的:

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; 

既然你说该表被声明为我知道你不能直接重写这样的逻辑,只是考虑方法论,也许这可以帮助你。