【问题标题】:How to efficiently handle slow CLOB reading from Oracle in .Net?如何有效地处理 .Net 中从 Oracle 读取的慢速 CLOB?
【发布时间】:2013-12-12 09:43:49
【问题描述】:

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

我们的环境: 甲骨文:11.2.0.1.0 VS:2010,专业版 Oracle.DataAccess.dll 从我的 Oracle 主页安装中引用: 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 中读取 TEXT 类型的对象一样快?

【问题讨论】:

    标签: c# performance oracle data-access-layer clob


    【解决方案1】:

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

    通过将 InitialLOBFetchSize 设置为 -1,可以从数据库中获取整个 LOB 数据以进行选择查询,而无需选择列表中的主键、ROWID 或唯一列。当 InitialLOBFetchSize 设置为 -1 时,会在 OracleDataReader 对象的 Read 方法调用期间获取并缓存整个 LOB 列数据。

    更多细节在这里: https://docs.oracle.com/cd/B28359_01/win.111/b28375/featData.htm#BABFGDGJ

    【讨论】:

    • 为我省去了几个小时的麻烦。补充一点,我的数据库在美国,只有当我尝试从新加坡连接时才看到这个问题,当我尝试通过在美国的服务器上托管我的应用程序进行连接时,它工作正常(检索速度不错)用于数据)。
    【解决方案2】:

    真的很难说到底是什么导致了缓慢。但我很确定 clob 通常不会像这样慢。

    最好确定是 C# 代码(odp.net 访问方式)还是 oracle 服务器是根本原因。在 oracle 端有多种识别方法。我会尝试的第一件事是使用 SET AUTOTRACE ON 在 sql*plus 上执行你的 SQL,这将告诉我们它在 oracle 服务器上的行为。

    • 此外,我们可以做出一些猜测或建议 在您的帐户上。如果您的数据长度始终小于 32K 并且 您可以将 oracle 升级到 12c,而不是尝试 varchar2 而不是 clob 或 blob,因为 12c 中的 varchar2 已扩展至 32K;
    • LOB 存储是 lob 的一个重要选项。 “选择 dbms_metadata.get_ddl( 'TABLE', 'your table' ) from dual;”将会说 表中的选项。对我来说,“ENABLE STORAGE IN ROW”应该 总是被使用。有关此选项的详细信息,请参阅 http://docs.oracle.com/cd/B28359_01/appdev.111/b28393/adlob_tables.htm#i1012988

    【讨论】:

      【解决方案3】:

      查看 Command 对象中的属性 FetchSize,请参见此处:Improve ODP.NET Performance

      你可以像这样得到行的大小:

         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
      

      在 C# 中是这样的:

      public int GetRowSize(OracleCommand cmd)
      {
         OracleDataReader dr = cmd.ExecuteReader();
         return (int)( dr.GetType().GetField("m_rowSize", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dr) );
      }
      

      您可以在启动应用程序时为每个不同的查询执行一次此函数,然后您可以重复使用该值。

      我记得我前段时间遇到过类似的问题。我的解决方案是选择没有任何 CLOB 列的表。为了获得 CLOB 值,我只为单个 CLOB 列和单个记录运行了一个额外的 SELECT(使用像你一样的 OracelDataReader)。

      我还找到了这个文档:Obtaining LOB Data

      【讨论】:

      • 我尝试为不同的值设置 FetchSize。在我当前的测试中,RowSize 是 176,但它不能解决我的问题。再一次,只有 CLOB 处理很慢。对于“较小”的类型,一切都很快。我曾经听说.Net 无法识别 CLOB 并尝试多次尝试将其转换为其他数据类型,这就是为什么它很慢...不知道这是否正确...?
      猜你喜欢
      • 2015-03-02
      • 1970-01-01
      • 2017-12-19
      • 1970-01-01
      • 2011-02-02
      • 2019-09-20
      • 1970-01-01
      • 2010-11-25
      • 1970-01-01
      相关资源
      最近更新 更多