【问题标题】:Optimise performance of an odbc data reader优化 odbc 数据读取器的性能
【发布时间】:2019-12-28 21:40:12
【问题描述】:

所以对于一个项目,我需要从 Acomba odbc 驱动程序中读取数据。 Acomba 是一个古老的会计软件。在幕后,acomba 将他的数据以 hexa 形式存储在平面文件中。他们提供了一个运行良好的 odbc 驱动程序,但速度很慢。

对于特定客户,他们有 17000 种产品。没什么太大的。但是从 odbc 驱动获取 17000 个产品需要超过 2m30。一些客户拥有接近 100 万种产品,因此性能成为一个大问题。

基本上,这段代码在 webapi 中。它获取数据,用它制作一个 csv 并在 httpResponse 中返回 csv 文件。生成 csv 大约需要 1 秒。所以这不是问题。

我尝试了一些东西:

        using (var db = new OdbcConnection($"DSN={_settings.DsnName}"))
        {
           await db.OpenAsync();
           OdbcCommand comm = new OdbcCommand(sql, db);
           OdbcDataReader dr = comm.ExecuteReader();
           while (dr.Read())
           {
              var col1 = dr.GetValue(0).ToString();
              var col2 = dr.GetValue(1).ToString();
              var col3 = dr.GetValue(2).ToString();
           }
        }

同样的事情,但有

dr.GetValues(destinationArray)

同样的事情,但使用 odbc 适配器

           var dt = new DataTable();
           using (var cmd = new OdbcCommand(sql, db))
           using (var adapter = new OdbcDataAdapter(cmd))
           {
              adapter.Fill(dt);
           }

所有这些最终都需要 2 分钟到 2 分钟 20 分钟。

这个特定表的问题是有 150 列。处理所有这 150 列需要花费所有时间。

试图寻找一种方法来优化它,但最终,我发现的所有代码都与我写的基本相同。

这是一个转折点!

如果我在 Excel 或 Access 中打开 odbc 连接,它们都可以在 5 秒内建立一个表格并显示它。我一直向下滚动,所以实际上加载了数据。它不仅显示前 50 行。

有人知道如何在 C# 中获得同样的性能吗?

感谢您的宝贵时间!

【问题讨论】:

    标签: odbc odbcdatareader


    【解决方案1】:

    我找到了使 ODBC 连接更快的方法。基本上,这个旧的 odbc 驱动程序是一个 COM。事实证明,当您在单线程单元与多线程中时,COM 对象运行得更快。所以我使用了这篇文章中发布的解决方案: http://ryanhaugh.com/archive/2014/05/24/supporting-sta-threads-in-web-api/

    public static class TaskFactoryExtensions
    {
        private static readonly TaskScheduler _staScheduler = new StaTaskScheduler(numberOfThreads: 1);
    
        public static Task<TResult> StartNewSta<TResult>(this TaskFactory factory, Func<TResult> action)
        {
            return factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, _staScheduler);
        }
    }
    

    我是我的 api 调用,我这样做:

    Task<DataTable> responseTask = Task.Factory.StartNewSta(() => GetData(sqlQuery));
    

    实际获取的数据,和旧的一模一样:

      private DataTable GetData(string value)
      {
         var dt = new DataTable();
    
         using (var db = new OdbcConnection($"DSN={_settings.DsnName}"))
         {
            db.Open();
            OdbcCommand comm = new OdbcCommand(value, db);
            using (OdbcDataAdapter da = new OdbcDataAdapter(comm))
            {
               da.Fill(dt);
            }
         }
    
         return dt;
      }
    

    我对所有使用 StartNewSta 获取数据的调用都使用了扩展方法。使用完全相同的代码,它从 2 分 30 秒变为 9 秒

    所以快速 COM 对象的关键是 STA 线程!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-08
      • 2020-11-20
      相关资源
      最近更新 更多