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);
                }

ADO.. NET损害性能:我怎样才能防止DataReader花费这么长时间

这可能会有所帮助,尽管缺乏关于您实际如何使用阅读器的信息。

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加载数据作为一个流。然后,您可以使用GetBytesGetChars方法来指定开始读取操作的字节位置,以及为返回的数据指定有限的缓冲区大小。

当您指定SequentialAccess时,您需要按照返回的顺序从列中读取,尽管您不需要读取每个列。一旦读取了返回的数据流中的某个位置,就不能再从DataReader读取该位置或之前的数据。当使用OleDbDataReader时,您可以重新读取当前列值,直到读取超过它。当使用SqlDataReader时,只能读取一个列值一次。

关于增加CommandTimeout属性,请看这篇文章:

增加SQL命令的超时时间

当您期望命令花费一定的时间时,应该要求更长的超时时间,并允许命令在超时之前返回。当超时发生时,需要几秒钟才能从中恢复。这一切都是可以避免的。您可能希望度量超时所需的时间,并尽可能地将其指定为接近实际命令超时需求的时间,因为较长的超时可能会引发一些其他潜在问题,而过长的超时则无法检测到这些问题。当命令超时时,问问自己如何处理较小的结果集,或者如何改进查询以运行得更快。