【问题标题】:ADO.NET DbCommand.ExecuteReader hangs on certain queries (Oracle XE 11g)ADO.NET DbCommand.ExecuteReader 在某些查询上挂起 (Oracle XE 11g)
【发布时间】:2019-06-28 18:26:30
【问题描述】:

当我们的客户发出访问其 Oracle XE 11g 数据库的请求时,我们的 C#/ASP.NET 应用程序遇到了一个非常特殊的问题。这通过使用 ODP.NET NuGet 包的 ADO.NET 上的普通 SQL 实现。

我们的应用程序托管在公共服务器上,而这个特定的数据库则私下托管在客户的场所。即,我们已获得带有凭据的连接字符串,并且他们已将我们的公共 IP 列入白名单,以便应用程序查看并与他们的数据库通信。

该方案在大多数情况下都运行良好。但是,有一组查询(实际上是参数略有不同的单个基本查询)会导致以下 C# 代码行挂起:

var reader = cmd.ExecuteReader(CommandBehavior.Default);

SELECT 并不简单,但也不是很复杂:

SELECT "T00_".*
FROM (
 SELECT ROWNUM "__ROWNUM",
  "T0_".*
 FROM (
  SELECT "T1_"."FIELD1" "F1",
   "T2_"."FIELD2" "F2",
   "T3_"."FIELD3" "F3",
   "T4_"."FIELD4" "F4"
  FROM "TABLE1" "T1_"
  LEFT OUTER JOIN "TABLE2" "T2_" ON ("T1_"."KEY2" = "T2_"."KEY")
  LEFT OUTER JOIN "TABLE3" "T3_" ON ("T1_"."KEY3" = "T3_"."KEY")
  LEFT OUTER JOIN "TABLE4" "T4_" ON ("T1_"."KEY4" = "T4_"."KEY")
  ORDER BY "T1_"."KEY2",
   "T1_"."KEY3"
  ) "T0_"
 ) "T00_"
WHERE "T00_"."__ROWNUM" <= 50

TABLE1 中有几百行,如预期的那样,上面的 SELECT 返回其中的 50 行。但只是稍微改变它,例如请求 62 行而不是 50 行,或者将一个 JOIN-ed 表中的一个字段添加到 ORDER BY,足以导致挂起。没有错误,没有超时 - 调用线程只是永远挂在 ExecuteReader 行上。

我们已经进行了很多实验,但导致挂起的更改似乎没有什么特别的意义。

客户声称他们的其他(本地)应用程序对此数据库服务器没有问题,因此问题一定出在我们的应用程序中。我倾向于同意,因为通过 TOAD 执行时所有查询都运行良好。它们仅在从我们的应用程序执行时挂起。我还没能把这些点联系起来......

令人困惑的部分是,我们的 ASP.NET 应用程序成功地从许多连接的数据库引擎(包括其他 Oracle 版本)为我们的客户检索数据,而我在那里没有看到此类问题。

有没有其他人通过 ADO.NET 在 Oracle XE 中遇到过类似的行为?你建议我在我们这边尝试什么?告诉客户切换数据库目前不是一种选择。

【问题讨论】:

  • 你检查过正在使用的索引吗?
  • 你能发布执行计划吗?
  • 另外,您可能会获得读卡器锁。你能用 NOLOCK 运行阅读器吗?试试看是否能解决问题。
  • 检查执行计划并没有发现任何可疑之处。索引按预期使用,并且 TOAD 设法快速执行相同的 SELECT 并且没有任何问题。事实证明,如果我在调用 ExecuteReader 之前更改 OracleCommand 实例上的 FetchSize 属性,我们的应用程序就会停止出现问题。 128 kb 的默认值似乎有问题,这让我相信我们在 ODP.NET 库中发现了一个错误。还不能 100% 确定。
  • 我也有这个问题,结果集非常大(25M 记录)。当我手动将 FetchSize 设置为 10000 时,它解决了这个问题。对于大型查询,可能有一个最佳 FetchSize,我将进行更多试验并报告哪种尺寸最适合我。

标签: c# asp.net oracle


【解决方案1】:

在使用 ExecuteReader() 函数后,de OracleCommand 类上的 FetchSize 属性的默认值似乎存在问题,导致锁定。 手动更改 FetchSize 属性为我解决了这个问题:

((OracleCommand)cmd).FetchSize = 1000000;

值 1000000 使我能够在大约 20 秒内将 100K 记录写入文件。 使用较低的 FetchSize 值 (1000-10000),这会增加到大约 60-100 秒。

【讨论】:

  • FWIW,我从来没有真正解决过这个问题,至少不是通过代码。我已经玩弄了 FetchSize 设置以及其他许多东西,是的。不幸的是,一段时间后,无论我做什么,问题总是又回来了。最后,我们将问题归咎于该特定客户的 Oracle 和网络硬件组合,因为它是许多其他使用 Oracle 的客户中唯一遇到这些不可预知的挂起的客户。请求偶尔重新启动他们的 Oracle 数据库服务是一个很好的解决方案,就像我可以在代码中提出的任何疯狂的配置调整一样。 HTH。
  • 对我来说,它现在似乎运作正常。您是否查看过 Oracle 客户端库的版本?我在使用不同版本的 Oracle 客户端时遇到了一些奇怪的问题,似乎需要非常具体的配置才能使用与其他软件(如 .NET)的集成。如果安装中的次要设置不同,我会收到难以理解的错误。
  • 我使用的是托管 ODP.NET,它不需要安装 Oracle 客户端,除了连接字符串和代码指定的内容之外没有其他特殊配置。我很高兴改变对你有用!
  • 抱歉,我使用的是 Oracle 托管数据访问 NuGet 包,过去我使用的是常规数据访问包,它需要 Oracle 客户端。我没有注意到我不再需要 Oracle 驱动程序。 stackoverflow.com/questions/7819861/…
猜你喜欢
  • 2013-05-02
  • 2014-10-20
  • 1970-01-01
  • 2014-10-03
  • 2013-10-23
  • 2018-07-13
  • 2013-11-29
  • 2021-10-18
  • 2016-04-26
相关资源
最近更新 更多