繁体   English   中英

如何提高存储过程的执行性能?

[英]How to improve stored procedure execution performance?

我的任务是从Oracle数据库调用存储过程。 存储过程定义如下:

CREATE OR REPLACE PROCEDURE my_st_proc
   (pname IN VARCHAR2, pdate IN date, o_rc OUT sys_refcursor, o_flag OUT number);

因此,它需要两个输入参数并返回两个输出参数,其中一个是游标。 当使用以下代码在pl \\ sql developer中测试性能时,它会在2-3秒内完成。

DECLARE   
   pname varchar2(300) := 'john doe';  
   pdate date := to_date('01/01/1900','dd/mm/yyyy');

   o_flag number;
   o_data sys_refcursor;

   --MyRec describes the fields, returned by the cursor
   TYPE MyRec IS RECORD 
        (cAccount VARCHAR2(20), cBalance number, cDate date, cCurr varchar2(8));
   rec MyRec;
BEGIN   
    my_st_proc(pname,pdate,o_data,o_flag); 
    dbms_output.put_line(o_flag);

    LOOP
        FETCH o_data INTO rec;
        EXIT WHEN o_data%NOTFOUND;
        dbms_output.put_line(
            rec.cAccount||','||rec.cBalance||','||rec.cDate||','||rec.cCurr);
    END LOOP;

    close o_data;
END;

但是,当我通过ODP.Net调用存储过程时,最多需要两秒钟才能完成(3-5秒)。

const string p_name = "pname";
const string p_date = "pdate";
const string p_data = "o_data";
const string p_flag = "o_flag";

using (var connection = new OracleConnection("my connection"))
{
    var command = connection.CreateCommand();
    command.CommandType = CommandType.StoredProcedure;
    command.CommandText = "my_st_proc";

    var pname = command.Parameters.Add(p_name, OracleDbType.Varchar2);
    pname.Direction = ParameterDirection.Input;
    var pdate = command.Parameters.Add(p_date, OracleDbType.Date);
    pdate.Direction = ParameterDirection.Input;

    command.Parameters.Add(p_data, OracleDbType.RefCursor).Direction = 
        ParameterDirection.Output;

    var pflag = command.Parameters.Add(p_flag, OracleDbType.Int32);
    pflag.Direction = ParameterDirection.Output;

    if (command.Connection.State != ConnectionState.Open)
        command.Connection.Open();

    command.Parameters[p_name].Value = name;
    command.Parameters[p_date].Value = date;

    DateTime bdate = DateTime.Now;
    command.ExecuteNonQuery();

    if (((OracleDecimal)command.Parameters[p_flag].Value).ToInt32() == 1)
    {

    }
    else
    {
        using (var oreader = command.ExecuteReader())
        {
            if (oreader != null)
            {
                try
                {
                    while (oreader.Read()){ }
                }
                finally
                {
                    oreader.Close();
                }
            }
        }
    }
    MessageBox.Show(DateTime.Now.Subtract(bdate).ToString());
}

最耗时的代码行似乎是

command.ExecuteNonQuery();

command.ExecuteReader()

游标返回的行数不超过10-15,很少,并且通过阅读器读取它们确实需要毫秒。 所以我想这不是FetchSizeRowSize问题。

在这种情况下,我能做些什么来提高ODP.Net的性能?

首先,您的功能包括打开数据库。 我猜在您的其他工具中,您已经完成了连接并刚刚执行了命令。 根据您的数据库安全性和位置,这很容易花费1-10秒。

我认为这实际上不会使您CommandType.StoredProcedure几秒钟,但是您从未使用过CommandType.StoredProcedure 相反,您自己构建了SQL。 让ODP.Net对此担心。 只需传递正确的命令类型和过程名称作为文本即可。

首先确保执行计划实际上是相同的。

与您的DBA一起工作,并请他们为独立运行(aqua数据工作室)和odp.net通话获取解释计划,并确认它们实际上是相同的。 如果不是,那可能会解释您的问题。 然后,您可以尝试在连接字符串中添加“ enlist = false”,但更好的方法是让DBA更新相关表的统计信息,以期解决缓慢的计划。 有关更多信息,请参见https://stackoverflow.com/a/14712992/852208

我也遇到过同样的问题,这归结为oracle在涉及分布式事务时对执行计划不太乐观。

上面的答案来自: https : //stackoverflow.com/a/15886630/852208 从本质上讲,这是“可以从X运行,但不能从Y运行”,因此它可能是重复的,但我们会看到。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM