Oracle存储过程在数据库中运行并返回一些数据行,耗时30秒。 现在,调用此过程并填充DataAdapter然后填充DataSet需要在C#.NET应用程序中使用1m40。
测试时发现,在调用存储过程后,使用DataReader并使用Read()函数读取数据,再次需要1m40s aprox的总时间。
任何想法可能导致这些瓶颈以及如何摆脱它们? 提前致谢!
编辑:添加了代码
OracleConnection oracleConnection = Connect();
OracleCommand oracleCommand = CreateCommand(2);
OracleDataReader oracleDataReader = null;
if (oracleConnection != null)
{
try
{
if (oracleConnection.State == ConnectionState.Open)
{
oracleCommand.Connection = oracleConnection;
oracleDataReader = oracleCommand.ExecuteReader();
DateTime dtstart = DateTime.Now;
if (oracleDataReader.HasRows)
{
while (oracleDataReader.Read())
{
/* big Bottleneck here ... */
// Parse the fields
}
}
DateTime dtEnd = DateTime.Now;
TimeSpan ts = new TimeSpan(dtEnd.Ticks - dtstart.Ticks);
lblDuration2.Text = "Duration: " + ts.ToString();
Disconnect(oracleConnection);
}
答案 0 :(得分:1)
这可能会有所帮助,尽管缺乏有关您如何使用阅读器的信息。
using (var cnx = Connect())
using (var cmd = CreateCommand(2)) {
try {
if (cnx.State == ConnectionState.Close) cnx.Open()
// The following line allows for more time to be allowed to
// the command execution. The smaller the amount, the sooner the
// command times out. So be sure to let enough room for the
// command to execute successfuly
cmd.CommandTimeout = 600;
// The below-specified CommandBehavior allows for a sequential
// access against the underlying database. This means rows are
// streamed through your reader instance and meanwhile the
// program reads from the reader, the reader continues to read
// from the database instead of waiting until the full result
// set is returned by the database to continue working on the
// information data.
using (var reader = cmd.ExecuteReader(
CommandBehavior.SequentialAccess)) {
if (reader.HasRows)
while (reader.Read()) {
// Perhaps bottleneck will disappear here...
// Without proper code usage of your reader
// no one can help.
}
}
} catch(OracleException ex) {
// Log exception or whatever,
// otherwise might be best to let go and rethrow
} finally {
if (cnx.State == ConnectionState.Open) cnx.Close();
}
}
有关命令行为的更多详细信息:Command Behavior Enumeration。
直接来自MSDN:
顺序访问
为 DataReader 提供一种方法来处理包含具有大二进制值的列的行。 SequentialAccess 不是加载整行,而是使 DataReader 以数据流的形式加载数据。然后,您可以使用 GetBytes 或 GetChars 方法指定启动读取操作的字节位置,以及返回数据的有限缓冲区大小。
指定 SequentialAccess 时,您需要按照返回的顺序读取列,但不需要读取每列。一旦您读取了返回的数据流中的某个位置,就无法再从 DataReader 中读取该位置或之前的数据。使用OleDbDataReader时,您可以重读当前列值,直到读过它为止。使用SqlDataReader时,您只能读取一次列值。
至于增加CommandTimeout属性,请看一下这篇文章:
Increasing the Command Timeout for SQL command
当您希望命令花费一定的时间时,需要更长的超时时间并允许命令在超时之前返回。发生超时时,需要几秒钟才能从中恢复。所有这一切都可以避免。您可能希望测量超时所需的时间,并将其指定为尽可能接近实际命令超时要求,因为较长的超时可能会导致一些其他潜在问题,这些问题在超时时间过长时无法检测到。发生命令超时时,请问自己如何处理较小的结果集,或者如何改进查询以加快运行速度。