【发布时间】: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,我将进行更多试验并报告哪种尺寸最适合我。