注意:我考虑过首先在DBA Exchange上发布此内容,但考虑到这是一个.NET客户端问题,我认为最好先问这里。
我有两个存储在Oracle 11g开发服务器中的函数,这些函数使用ODP.NET调用(使用Oracle.ManagedDataAccess而不是Oracle.DataAccess)。
这两个函数在SQL Developer中是闪电般快速的(有意义的是,它们只是简单的查询只选择了大约20,000条记录),但是当我从C#app中解雇时,性能(使用System.Diagnostics.Stopwatch测量)不是很好。使用ODP.Net。
以下是结果:(忽略'转换时间和撰写时间,它们不是查询过程的一部分)
Connecting time - GET_TVM_ALL: 00:00:00.0553501
Query time - GET_TVM_ALL: 00:00:05.3467058
Conversion time: 00:00:07.6508273
Connecting time - GET_TVM_STATUS_ALL_FUNC: 00:00:00.0006773
Query time - GET_TVM_STATUS_ALL_FUNC: 00:00:00.0256008
Conversion time: 00:00:03.7280097
Composing time: 00:00:00.0157274
Total Elapsed: 00:00:16.7796351
GET_TVM_ALL的执行时间为5秒,非常高。更令人惊讶的是,第二个查询要快得多。这很奇怪,因为毫无疑问,对于超过20倍的记录数量来说,这是一个更复杂的查询。
所以我换了它们,这就是结果:
Connecting time - GET_TVM_STATUS_ALL_FUNC: 00:00:00.0573807
Query time - GET_TVM_STATUS_ALL_FUNC: 00:00:05.2981962
Conversion time: 00:00:03.6474905
Connecting time - GET_TVM_ALL: 00:00:00.0007322
Query time - GET_TVM_ALL: 00:00:00.0070785
Conversion time: 00:00:07.2473809
Composing time: 00:00:00.0154049
Total Elapsed: 00:00:16.2268687
正如您所看到的,看起来第一个查询总是很慢,无论其内容如何。为了证明这一点,我做了一个愚蠢的虚拟函数:
CREATE OR REPLACE FUNCTION GET_DUMMY
RETURN SYS_REFCURSOR
AS
-- REFCURSOR to return data
pCursor SYS_REFCURSOR;
BEGIN
OPEN pCursor FOR SELECT 1 FROM DUAL;
RETURN pCursor;
END;
现在,从我的代码中调用它,让我们来看看:
Connecting time - GET_DUMMY: 00:00:00.0581149
Query time - GET_DUMMY: 00:00:05.4103165
Conversion time: 00:00:00.0005617
Connecting time - GET_TVM_STATUS_ALL_FUNC: 00:00:00.0006580
Query time - GET_TVM_STATUS_ALL_FUNC: 00:00:00.0759243
Conversion time: 00:00:03.7577602
Connecting time - GET_TVM_ALL: 00:00:00.0000489
Query time - GET_TVM_ALL: 00:00:00.0037654
Conversion time: 00:00:07.5071360
Composing time: 00:00:00.0152159
Total Elapsed: 00:00:16.7819147
所以这证明了这一点,我运行的第一个查询总是很慢。
额外信息:我正在为我呼叫的每个功能打开和关闭新连接。
顺便说一句,这是我的助手功能:
public static List<T> ExecuteFunction<T>(string strConnection, string strFunction, OracleDbType returnType, List<DataOracleParameter> parameterList) where T : new()
{
Stopwatch watch = new Stopwatch();
using (OracleConnection objConnection = new OracleConnection(strConnection))
{
// Create the command object and set attributes
OracleCommand objCommand = new OracleCommand(strFunction, objConnection);
objCommand.CommandType = CommandType.StoredProcedure;
// Set the return parameter and type
OracleParameter returnValue = new OracleParameter();
returnValue.OracleDbType = returnType;
returnValue.Direction = ParameterDirection.ReturnValue;
objCommand.Parameters.Add(returnValue);
// Set additional parameters
if (parameterList != null && parameterList.Count > 0)
{
foreach (DataOracleParameter parameter in parameterList)
{
OracleParameter inputValue = new OracleParameter();
inputValue.ParameterName = parameter.ParameterName;
inputValue.OracleDbType = parameter.ParameterType;
inputValue.Value = parameter.ParameterValue;
inputValue.Direction = ParameterDirection.Input;
objCommand.Parameters.Add(inputValue);
}
}
// Create a data adapter to use with the data set
OracleDataAdapter dataAdapter = new OracleDataAdapter(objCommand);
// Create and fill the dataset
DataSet dataSet = new DataSet();
watch.Start();
dataAdapter.Fill(dataSet);
watch.Stop();
Console.WriteLine("Query time - {0}: {1}", strFunction, watch.Elapsed);
List<T> valueList = dataSet.Tables[0].ToList<T>();
return valueList;
}
}
答案 0 :(得分:1)
首先,我建议您在OracleCommand对象上调整FetchSize。
答案 1 :(得分:0)
我有同样的问题,我重命名了iis应用程序池,简称,它解决了我的问题,虽然不解但对我有用
答案 2 :(得分:0)
我今天遇到了这个问题,它使我想起了十年前与Microsoft的Oracle驱动程序有关的问题。使用参数时,速度很慢,但是如果我们转换为文字,则可以按预期工作。我一直认为,参数是最佳做法,所以这对我来说很困惑。
原来是Microsoft适配器,甚至他们都承认这是垃圾。切换到ODP.net即可解决此问题。
快进到今天...我在使用Oracle的Managed ODP.net时遇到了同样的现象。当我使用参数(又称正确的方法)时,甚至花了很长时间才能运行查询execute。
using (OracleCommand cmd = new OracleCommand(sql, conn))
{
cmd.Parameters.Add("FROM_DATE", fromDate);
cmd.Parameters.Add("DISTRIBUTOR_ID", distributorId);
using (OracleDataReader reader = cmd.ExecuteReader()) // Bottleneck here
{
}
}
当我切换到原义时(再次,这是一种可怕的做法),它立即运行。
sql = sql.Replace(":DISTRIBUTOR_ID", distributorId.ToString())
.Replace(":FROM_DATE", string.Format("'{0:dd-MMM-yyyy}'", fromDate));
using (OracleCommand cmd = new OracleCommand(sql, conn))
{
using (OracleDataReader reader = cmd.ExecuteReader())
{
}
}
令人失望...托管ODP是否有问题?福禄克?我不会将其用作标准做法,但是现在,我将文字保留在此特定代码中。我的应用程序控制这些值,因此它是SQL注入安全的。
P.S。我知道我应该使用Oracle的to_date
和显式参数声明。