我的任务是从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,足够少,通过阅读器读取它们需要几毫秒;所以我认为它不是FetchSize
或RowSize
问题。
在这种情况下,我有什么办法可以提高ODP.Net的性能吗?
答案 0 :(得分:1)
首先,您的功能包括打开数据库。我想在你的其他工具中,你已经完成了连接,只是执行了命令。根据您的数据库安全性和位置,这需要1-10秒。
我认为这实际上不会让你获得秒数,但你从未使用CommandType.StoredProcedure
。相反,你自己构建SQL。让ODP.Net担心这一点。只需将正确的命令类型和过程名称作为文本传递。
答案 1 :(得分:0)
首先确保执行计划实际上是相同的。
与您的DBA合作并要求他们为独立运行(aqua data studio)和您的odp.net呼叫捕获解释计划,并确认它们实际上是相同的。如果他们不是,那么这可能会解释你的问题。然后,您可以尝试将“enlist = false”添加到您的连接字符串,但更好的是让DBA更新相关表的统计信息,希望能够修复慢速计划。有关详细信息,请参阅https://stackoverflow.com/a/14712992/852208。
我遇到了同样的问题,而且当涉及分布式事务时,oracle对执行计划不太乐观。
上述答案来自:https://stackoverflow.com/a/15886630/852208。这基本上是“从X运行而不是从Y运行”,所以它可能是重复但我们会看到。