4

我目前正在评估 Oracle 的 ODP.NET DataProvider,我遇到了一个在我们的一个测试用例中弹出的问题:当使用不同的参数类型执行相同的命令文本时,第一个执行命令的参数类型将用于以下所有内容命令。

以下面的代码为例:

const int sampleInt32 = 1234567890;
const string sampleNvarchar = "someTestString";

const string sqlCommandtext = "SELECT :PARAM PARAM FROM DUAL";
using (OracleConnection connection = new OracleConnection(builder.ConnectionString))
{
    connection.Open();

    //Test 1 - Int 32
    using (OracleCommand commandInt32 = connection.CreateCommand())
    {
        commandInt32.CommandText = sqlCommandtext;
        commandInt32.Parameters.Add("PARAM", OracleDbType.Int32, sampleInt32, ParameterDirection.Input);
        using (IDataReader reader = commandInt32.ExecuteReader())
        {
            while (reader.Read())
            {
                int resultInt32 = (int)reader.GetDecimal(0);
                Assert.AreEqual(sampleInt32, resultInt32);
            }
        }
    }
    //Test 2 - NVarchar
    using (OracleCommand commandNVarchar = connection.CreateCommand())
    {
        commandNVarchar.CommandText = sqlCommandtext;
        commandNVarchar.Parameters.Add("PARAM", OracleDbType.NVarchar2, sampleNvarchar, ParameterDirection.Input);
        using (IDataReader reader = commandNVarchar.ExecuteReader())
        {
            while (reader.Read())
            {
                string resultNVarchar = reader.GetString(0);
                Assert.AreEqual(sampleNvarchar, resultNVarchar);
            }
        }
    }
}

如果 commandInt32 在 commandNVarchar 之前执行,则 commandNVarchar 的执行失败并出现 ORA-01722 - 无效编号。如果切换了顺序,因此首先执行 commandNVarchar,它会失败,并在 reader.GetDecimal 上显示“Specified cast is not valid”。

到目前为止,我已经尝试设置 StatementCacheSize=0; 池化=假;StatementCachePurge=true 作为 ConnectionString 参数,但我无法让它工作。

有什么我遗漏的,还是有其他值得尝试的选择?

编辑:也许需要/需要一些背景知识:我们不直接在我们的应用程序中使用 ODP 或任何其他 Dataprovider(或者至少:我们正在实现这个目标),在这之间有一个 DataLayer执行数据库/提供商特定的优化和连接健康监控,...

例如,在这一层中,可以调用 StoredProcedures,具有参数类型调整的选项。我们的一些程序将 Clob 作为参数类型,因为有时值可能比 x 个字符长,但很可能会更短。因此,在通过 ArrayBindCount 设置为 y 的 ExecuteNonQuery 执行之前,检查参数值是否可以作为 varchar 传递(Nclob 作为 Nvarchar)。“重新绑定”将执行 2500 条记录的时间从大约 500 毫秒减少到 200 毫秒,代价是损失了几毫秒的检查字符串长度。而这种重新绑定只有在参数类型可以改变的情况下才能完成。如果没有此选项,我们将需要每次都将其作为 Clob 执行,从而降低性能。

4

4 回答 4

3

据我了解,SELECT列表中不支持参数绑定。我很惊讶这完全有效,以至于我不得不运行您的代码才能亲眼看到它。我相信客户端允许该 SQL 语句执行是一个错误。

无论如何,我在测试用例之间插入了以下行以使它们都起作用:

connection.PurgeStatementCache();

但是,这似乎只适用于托管客户端(我已经尝试使用版本 4.112.3.60)。正如您所描述的,普通客户仍然失败。

于 2013-07-31T15:53:10.760 回答
2

两件事情。用作连接字符串参数时,配置变量需要有空格,即

Statement Cache Size=0;

您使用的格式可以直接在配置中使用:http: //docs.oracle.com/html/E10927_01/featConfig.htm#CJABCACG

http://docs.oracle.com/html/E10927_01/featOraCommand.htm#CIHCAFIG

您可以使用相同的配置部分来启用跟踪 - 比较跟踪可能会让您了解正在发生的事情。

我相信 PurgeStatementCache (不确定 StatementCachePurge 是否存在)是一个运行时命令,即

connection.PurgeStatementCache
于 2013-07-31T16:11:45.637 回答
2
Metadata Pooling = false;

我们的应用程序使用 Oracle 12c 和 ODP.Net Managed Provider

使用时OracleCommandBuilder.DeriveParameters(),尽管添加/删除/更新参数,我们总是看到从存储过程返回相同的参数。我们只会在重新启动 IIS 进程后才能看到更改。

唯一有效的解决方案是Metadata Pooling = false;在 Oracle 连接字符串中设置

我们在这里或 Oracle 论坛上提到的以下内容没有成功:

connection.PurgeStatementCache();

Statement Cache Size=0;

Pooling = false;
于 2015-10-30T18:45:02.430 回答
1

您连接到哪个版本的 Oracle?这可能是绑定变量峰值(或缺少峰值)问题。该功能是在 9i 中引入的,但一直到 10 都存在一些问题。您可以尝试执行以下命令,看看是否可以在没有 ODP.net 的情况下重现该问题:

var param varchar2(255)
exec :param:='TEST';
select :param FROM DUAL;

将“param”上的类型从 varchar2 更改为 number 并更改值并重新执行以查看会发生什么。

您也可以尝试在不同的连接而不是共享的连接下执行命令。

最后,您可以简单地重命名语句中的绑定变量,相对于类型(即:paramNum 或:paramString)。除非 cmd.BindByName 设置为 true,否则您在 .net 端为参数指定的名称无关紧要。默认情况下它是假的,并且变量是按照它们添加的顺序绑定的。

于 2013-07-31T12:10:58.170 回答