.Net 中 Oracle DataReader 的大性能问题

Posted

技术标签:

【中文标题】.Net 中 Oracle DataReader 的大性能问题【英文标题】:Big Performance Problems With Oracle DataReader in .Net 【发布时间】:2010-11-10 04:16:42 【问题描述】:

我有一些 Oracle 程序可以生成/返回大量数据,我需要将这些数据写入文件。我目前正在尝试使用数据阅读器来完成。它似乎正在工作,我已经成功生成了一个 479mb 的文件,没有任何问题。从我检索 dataReader 到完成文件的时间不到 4 分钟。

但我为特定过程获得的 dataReader 是正在爬行。它慢得令人难以置信。我修改了我的代码以尝试更好地了解正在发生的事情......

System.Diagnostics.Debug.Write("Performing .Read() on DataReader: ")
Dim d1 As DateTime = DateTime.Now
Dim result As Boolean = myDataReader.Read()
Dim ts As TimeSpan = DateTime.Now.Subtract(d1)
System.Diagnostics.Debug.WriteLine(ts.ToString)

有趣的是,我的输出最终看起来像这样:

Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:00:00
Performing .Read() on DataReader: 00:07:33.5037500

我真的不知道下一步该做什么。我看不出占用 07:33.5037500 的行有任何独特或不同之处。有什么建议吗?

编辑:

感谢大家的回复。首先,据我所知,没有抛出异常。正如建议的那样,我已经查看了这个表现出上述行为的特定过程,而过程非常庞大;但看起来它使用了很多游标来填充 oracle 临时表。返回的 Ref Cursor 是一个 SELECT * FROM that temp table。

我正在编写一个 PL/SQL 块,该块将打开该游标以查看当我删除 .Net 代码时是否存在性能问题......希望这会有所帮助;但如果您有任何其他想法,我们将不胜感激。

再次感谢。这似乎是 PL/SQL 问题,而不是 .NET 问题。

【问题讨论】:

没有足够的信息来回答 atm...除了它抛出的异常是静默处理的吗? 您可能应该发布更多完整代码... 【参考方案1】:

数据库实际上在做什么?

带有 GROUP BY 或 ORDER BY 的查询可能需要生成完整的结果集,然后在返回一行之前对其进行排序/聚合。扫描大表的查询可能会在前几个块中找到 50 行,然后再读取另外十万个块,然后再找到另一个块。

我建议你忽略VB代码并发布数据库代码。

【讨论】:

这个过程非常庞大;但看起来它使用大量游标来填充 Oracle 临时表。返回的 Ref Cursor 是一个 SELECT * FROM that temp table。 那么我认为您几乎可以保证问题出在 PL/SQL 代码和查询中。向您的 DBA 寻求帮助以了解详细信息。【参考方案2】:

我假设当您说“特定过程”时,您的意思是您正在调用具有 OUT 参数的 Oracle 存储过程,该参数是 REF CURSOR。然后,您的 DataReader 将从过程返回的游标中获取。是这样吗?

如果是这样,您能否消除 .Net 代码并编写一个 PL/SQL 块来调用该过程并从游标中获取所有数据以查看您是否在那里获得相同的行为? Oracle 在打开游标时不会具体化数据——它会在客户端获取数据时具体化结果。因此,如果 Oracle 必须在找到第 N+1 行之前实现并过滤掉一堆数据,那么它可能需要做很多工作来获取第 N 行。如果您在数据库上运行的 PL/SQL 中看到相同的行为,那几乎可以肯定是正在发生的事情。如果您在 PL/SQL 块中没有发现任何问题,那么中间层肯定有问题。

【讨论】:

谢谢 - 是的,它是一个 OUT 参数,它是一个 REF CURSOR。我将在 PL/SQL 中尝试并进行比较。【参考方案3】:

对于您问题的原始版本,只有几个一般的 cmets:

如果您使用 Microsoft .NET Framework 的内置 System.Data.OracleClient 提供程序类,您可能会从 Oracle's own updated .NET Provider 获得更好的性能。

如果时间在每次运行前后发生变化,则 .NET 垃圾收集器可能正在处理您的示例中没有看到的一些内存使用情况(即,如果许多对象被实例化并被丢弃)。

【讨论】:

以上是关于.Net 中 Oracle DataReader 的大性能问题的主要内容,如果未能解决你的问题,请参考以下文章

检索大型记录集时 DataReader 挂起

如何使用 DataReader 读取数据库记录并将其添加到 DataTable

Oracle DataReader 在 GetDateTime 上出错

ADO.NET 四(DataReader)

DataReader + DropDownList ASP.NET 项目

在标签控件 (ASP.NET) 中显示来自 DataReader 的数据