ADO.. NET损害性能:我怎样才能防止DataReader花费这么长时间
本文关键字:DataReader 长时间 NET 性能 ADO | 更新日期: 2023-09-27 18:17:03
Oracle存储过程在数据库中运行并返回一些数据行,耗时30秒。现在,在c# . net应用程序中调用这个过程并填充DataAdapter以填充数据集需要1m40s。
测试,注意到在调用存储过程后使用DataReader和Read()函数顺序读取,再次花费大约1m40s的总时间。
知道是什么导致了这些瓶颈以及如何摆脱它们吗?提前感谢!
编辑:添加代码 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);
}
这可能会有所帮助,尽管缺乏关于您实际如何使用阅读器的信息。
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();
}
}
有关命令行为的更详细信息:命令行为枚举。
直接来自MSDN:
顺序存取
为DataReader提供一种方法来处理包含大二进制值的列的行。而不是加载整个行,SequentialAccess使DataReader加载数据作为一个流。然后,您可以使用GetBytes或GetChars方法来指定开始读取操作的字节位置,以及为返回的数据指定有限的缓冲区大小。
当您指定SequentialAccess时,您需要按照返回的顺序从列中读取,尽管您不需要读取每个列。一旦读取了返回的数据流中的某个位置,就不能再从DataReader读取该位置或之前的数据。当使用OleDbDataReader时,您可以重新读取当前列值,直到读取超过它。当使用SqlDataReader时,只能读取一个列值一次。
关于增加CommandTimeout属性,请看这篇文章:
增加SQL命令的超时时间
当您期望命令花费一定的时间时,应该要求更长的超时时间,并允许命令在超时之前返回。当超时发生时,需要几秒钟才能从中恢复。这一切都是可以避免的。您可能希望度量超时所需的时间,并尽可能地将其指定为接近实际命令超时需求的时间,因为较长的超时可能会引发一些其他潜在问题,而过长的超时则无法检测到这些问题。当命令超时时,问问自己如何处理较小的结果集,或者如何改进查询以运行得更快。