Oracle存储过程将光标慢速返回到C#,在TOAD上快速返回

时间:2017-02-16 21:57:03

标签: asp.net asp.net-mvc odp.net oracle12c odp.net-managed

我们使用asp.net mvc作为web应用程序,oracle 12C作为数据库,'Oracle.DataAccess.Client'(12.1.0,64位版本)用于连接Oracle数据库,我们的asp.net MVC应用程序运行于64位机器。

我们的一个存储过程将一个游标返回为out put参数。

现在,当我们在TOAD或SQL Developer上执行它时,相同的存储过程只需要不到一秒的时间,但是当C#执行相同的存储过程时,它需要大约35秒...... !!!回来TOAD,SQL Developer和asp.net iis服务器都在我的本地机器上,而Oracle服务器在不同的机器上。

在C#中,我记录了各种时间,比如打开连接需要多长时间,C#调用存储过程的时间戳以及它完成和返回的时间,将DataSet转换为多长时间C#列表。在观察完所有时间后,我们看到以下陈述需要35秒

            OracleDataAdapter loDataAdapter = new  OracleDataAdapter(loCommand);
            LogInfo("fill DataTable");//logs time stamp saying start
            loDataAdapter.Fill(loDataTable);
            LogInfo("fill DataTable",false);//logs time stamp saying Done
            loDataAdapter = null;

我们认为这可能是网络问题,如果是这种情况,toad和sql开发人员也应该花费相同的时间,因此网络不是问题。

我们尝试了什么: 我唯一的嫌疑是ODP.NET驱动程序,所以删除了所有oracle客户端并重新安装它们,没用。

现在试着看看我是否有必要在sqlnet.ora或tns文件连接上配置?但找不到任何......

这是完整的代码

public DataTable GetDataTable(string psStoredProcedure)         { LOGINFO(psStoredProcedure);

        //******************************************************************
        //Function.........GetDataTable
        //Description......Gets a data set (with the schema) from stored procedure
        //Input Param......(1)Stored procedure name
        //                 (2)Boolean to determine if we want to get the schema
        //Output...........Return DataTable 
        //
        //******************************************************************

        OracleCommand loCommand = new OracleCommand();
        OracleConnection loConnection = new OracleConnection(msConnectionString);
        DataTable loDataTable = new DataTable();

        //---Main Execution Block
        try
        {
            if (!(loConnection.State == ConnectionState.Open))
            {
                LogInfo("Open Conn");
                loConnection.Open();
                LogInfo("Open Conn",false);
            }

            //---Define the SelectCommand 
            if (moCommand == null)
            {
                loCommand = new OracleCommand();
            }
            else
            {
                loCommand = moCommand;
                moCommand = null;
            }

            loCommand.CommandText = psStoredProcedure;
            loCommand.Connection = loConnection;
            loCommand.CommandType = CommandType.StoredProcedure;

            //---Populate the dataset
            OracleDataAdapter loDataAdapter = new OracleDataAdapter(loCommand);
            LogInfo("fill DataTable");
            loDataAdapter.Fill(loDataTable);
            LogInfo("fill DataTable",false);
            loDataAdapter = null;
        }
        catch (Exception oExcep)
        {
            throw oExcep;
        }
        finally
        {
            //---Close the connection
            if (loConnection.State == ConnectionState.Open)
            {
                LogInfo("Close");
                loConnection.Close();
                LogInfo("Close", false);
            }

            loCommand = null;
            loConnection = null;
        }
        LogInfo(psStoredProcedure, false);
        return loDataTable;}

以下是PL / SQL In存储过程:

CREATE OR REPLACE PROCEDURE REF_LIST_INQ ( 
ivID          IN VARCHAR2 DEFAULT NULL,        
ivAID         IN VARCHAR2 DEFAULT NULL,
ivDID           IN VARCHAR2 DEFAULT NULL, 
ivSelection        IN VARCHAR2 DEFAULT NULL, 
ivStartDate        IN VARCHAR2 DEFAULT NULL,
ivEndDate          IN VARCHAR2 DEFAULT NULL,       
ocRefList     OUT ES_PACKAGE.cursorType,
ovReturnCode       OUT VARCHAR2,
ovErrorMsg         OUT VARCHAR2  
)
AS

cmdSQL       VARCHAR2(4000) := NULL;
whereCause   VARCHAR2(2000) := NULL;
selectCause  VARCHAR2(2000) := NULL;


BEGIN
    /************
 --Hundreds of lines of PL/SQL Code for
    -- dynamically creating sql statements 
    -- and assigning it to 'selectCause' and 'whereCause'
*************************/

    cmdSQL :=  selectCause || whereCause || ' ORDER BY SD.MODIFIED_DATE DESC, SD.REFERRAL_NUMBER';

    OPEN ocRefList FOR cmdSQL;
    ovReturnCode := '0';

    EXCEPTION WHEN OTHERS THEN
         ovErrorMsg := 'REF_LIST_INQ - ' || SUBSTR(SQLERRM,1,200);
         ovReturnCode := '-1';

END REF_LIST_INQ;
/

1 个答案:

答案 0 :(得分:0)

对我而言,这是一个答案,如果有人面临同样的情况可以尝试一下。

经过几天的研究,继C#声明帮助了我。

loCommand.FetchSize = loCommand.FetchSize * 18192;

根据我的理解(我不擅长描述,尝试我的水平最佳)这仅适用于64位版本,如果我们不指定' FetchSize'它将继续从Oracle DB上打开的游标中获取预定义的大小(我相信128k)数据,它将进行往返,直到游标提供的数据完成。

所以这里是完整的C#代码,但是一行代码产生了很大的不同。

    //******************************************************************
    //Function.........GetDataTable
    //Description......Gets a data set (with the schema) from stored procedure
    //Input Param......(1)Stored procedure name
    //                 (2)Boolean to determine if we want to get the schema
    //Output...........Return DataTable 
    //
    //******************************************************************

    OracleCommand loCommand = new OracleCommand();
    OracleConnection loConnection = new OracleConnection(msConnectionString);
    DataTable loDataTable = new DataTable();

    //---Main Execution Block
    try
    {
        if (!(loConnection.State == ConnectionState.Open))
        {
            LogInfo("Open Conn");
            loConnection.Open();
            LogInfo("Open Conn",false);
        }

        //---Define the SelectCommand 
        if (moCommand == null)
        {
            loCommand = new OracleCommand();
        }
        else
        {
            loCommand = moCommand;
            moCommand = null;
        }

        loCommand.CommandText = psStoredProcedure;
        loCommand.Connection = loConnection;
        loCommand.CommandType = CommandType.StoredProcedure;
//Here is the Hero
loCommand.FetchSize = loCommand.FetchSize * 18192;

        //---Populate the dataset
        OracleDataAdapter loDataAdapter = new OracleDataAdapter(loCommand);
        LogInfo("fill DataTable");
        loDataAdapter.Fill(loDataTable);
        LogInfo("fill DataTable",false);
        loDataAdapter = null;
    }
    catch (Exception oExcep)
    {
        throw oExcep;
    }
    finally
    {
        //---Close the connection
        if (loConnection.State == ConnectionState.Open)
        {
            LogInfo("Close");
            loConnection.Close();
            LogInfo("Close", false);
        }

        loCommand = null;
        loConnection = null;
    }
    LogInfo(psStoredProcedure, false);
    return loDataTable;}