C# 如何在.Net中有效地处理从Oracle读取CLOB的缓慢过程?

C# 如何在.Net中有效地处理从Oracle读取CLOB的缓慢过程?,c#,performance,oracle,data-access-layer,clob,C#,Performance,Oracle,Data Access Layer,Clob,在我的公司,我们有一个WPF应用程序,它可以连接到不同的数据库MS SQL、MySQL、SQLite和Oracle。我们有很多表,有时是200+,不问为什么,它非常复杂,我们的数据访问层有几个接口和虚拟/重写方法来处理特定数据库中的数据读取。这一点很重要,因为我们不像大多数教程所显示的那样专门处理一个表,而是动态创建了需要运行的特定于数据库的命令。在MS SQL、MySQL和SQLite下,一切都运行良好,但在Oracle中,CLOB读取速度非常慢。读取2000行数据需要40-50秒。不幸的是,

在我的公司,我们有一个WPF应用程序,它可以连接到不同的数据库MS SQL、MySQL、SQLite和Oracle。我们有很多表,有时是200+,不问为什么,它非常复杂,我们的数据访问层有几个接口和虚拟/重写方法来处理特定数据库中的数据读取。这一点很重要,因为我们不像大多数教程所显示的那样专门处理一个表,而是动态创建了需要运行的特定于数据库的命令。在MS SQL、MySQL和SQLite下,一切都运行良好,但在Oracle中,CLOB读取速度非常慢。读取2000行数据需要40-50秒。不幸的是,在大多数情况下,我们不能假设我们不需要CLOB类型,因为我们以xml格式存储金融数据,有时它的长度超过4000、8000甚至10k+字符。Im使用ODP.Net解决方案读取数据,这就是我所做的:

我们的环境: 甲骨文:11.2.0.1.0 VS:2010,专业版 Oracle.DataAccess.dll引用自我的Oracle home安装: C:\Oracle\ODP.NET\bin\4\Oracle.DataAccess.dll

以及我们解决方案中的测试代码:

财产:

private string ConnectionString
{
   get
   {
      return
         string.Format(
         "User Id={0}; Password={1}; POOLING=true;
         Data Source= (DESCRIPTION=(ADDRESS=
         (PROTOCOL=TCP)(HOST={2})(PORT={3})) (CONNECT_DATA=(SID={4})
         (SERVICE_NAME={5})));",
         "ourUser", "ourPassword", "ourHost", "ourPort", "ourSID",
         "ourDatabaseName");
        }
    }
要运行的命令:

string sql = "SELECT * FROM OurTable";
//This table contains at least one CLOB column
以及我们的测试代码:

List<object[]> readerList = new List<object[]>();

using (Oracle.DataAccess.Client.OracleConnection oraConn = new
    Oracle.DataAccess.Client.OracleConnection(ConnectionString))
{
   oraConn.Open();
   Oracle.DataAccess.Client.OracleCommand oraComm = new
      Oracle.DataAccess.Client.OracleCommand(sql);
   oraComm.CommandType = CommandType.Text;
   oraComm.Connection = oraConn;
   Oracle.DataAccess.Client.OracleDataReader oraReader;
   oraReader = oraComm.ExecuteReader();
   oraComm.InitialLOBFetchSize = -1;

   while (oraReader.Read())
   {
      object[] readObjects = new object[oraReader.FieldCount];
      oraReader.GetValues(readObjects);
      readerList.Add(readObjects);
   }

  oraConn.Close();
}
while迭代运行得非常慢,除非我们不需要读CLOB,因为在这里它会很快。 不幸的是,我不能制定特定于表的解决方案,因为并非在所有情况下我都知道我必须处理哪些表,有时会有动态创建的表

因此,问题是:
是否有任何解决方案可以使其与从MS SQL读取文本类型对象的速度一样快?

很难说到底是什么原因造成了这种速度慢。但我很确定clob通常不会像这样慢下来

最好缩小C代码、odp.net访问方式还是oracle服务器是根本原因的范围。在oracle端有多种识别方法。我要尝试的第一件事是在SQL*plus上执行SQL,并启用“自动跟踪”,这将告诉我们在oracle server上的行为

此外,我们还可以提出一些猜测或建议 因为你的缘故。如果数据长度始终小于32K,并且 您可以将oracle升级到12c,然后尝试使用varchar2代替clob或 blob,如12c中的varchar2已扩展到32K; LOB存储是LOB的一个重要选项。“选择 dbms_metadata.get_ddl'TABLE'、'your TABLE'from dual;”将说明 表中的选项。对我来说,“在行中启用存储”应该 总是被使用。有关此选项的详细信息,请参见 查看Command对象中的属性FetchSize,请参见此处:

您可以按如下方式获得行的大小:

   Public Function GetRowSize(ByVal cmd As OracleCommand) As Integer
      Dim dr As OracleDataReader
         dr = cmd.ExecuteReader()
         Return CInt(dr.GetType.GetField("m_rowSize", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic).GetValue(dr))
   End Function
public int GetRowSize(OracleCommand cmd)
{
   OracleDataReader dr = cmd.ExecuteReader();
   return (int)( dr.GetType().GetField("m_rowSize", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dr) );
}
在C中,它如下所示:

   Public Function GetRowSize(ByVal cmd As OracleCommand) As Integer
      Dim dr As OracleDataReader
         dr = cmd.ExecuteReader()
         Return CInt(dr.GetType.GetField("m_rowSize", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic).GetValue(dr))
   End Function
public int GetRowSize(OracleCommand cmd)
{
   OracleDataReader dr = cmd.ExecuteReader();
   return (int)( dr.GetType().GetField("m_rowSize", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dr) );
}
当应用程序启动时,可以为每个不同的查询执行此函数一次,然后可以重用该值

我记得不久前我也有类似的问题。我的解决方案是选择没有任何CLOB列的表。为了获得CLOB值,我使用OracelDataReader运行了一个额外的SELECT,就像您一样,只针对单个CLOB列和单个记录


我还发现了以下文档:

我知道这是旧文档,但我遇到了类似的问题。在OracleCommand上设置InitialLOBFetchSize=-1对我来说有很大的不同。我的CLOB列具有一致且合理的大小,因此此设置对我来说是有意义的

通过将InitialLOBFetchSize设置为-1,可以从数据库中为select查询获取整个LOB数据,而不需要select列表中的主键、ROWID或unique列。当InitialLOBFetchSize设置为-1时,在OracleDataReader对象上的读取方法调用期间,将获取并缓存整个LOB列数据

详情如下:

我尝试为不同的值设置FetchSize。在我当前的测试中,RowSize是176,但它不能解决我的问题。再一次,只有CLOB处理速度慢。对于较小的类型,一切都很快。我曾经听说.Net无法covnert CLOB,并尝试将其转换为其他数据类型,这就是它速度慢的原因…不知道这是否正确…?为我节省了数小时的麻烦。更重要的是,我的数据库在美国,只有当我试图从新加坡连接时,我才发现这个问题,当我试图通过在美国的服务器上托管我的应用程序进行连接时,它的工作方式非常好,数据检索速度非常快。