优化 odbc 数据的性能 reader

Optimise performance of an odbc data reader

所以为了一个项目,我需要从Acomba odbc驱动读取数据。 Acomba是一个古老的会计软件。在幕后,acomba 将他的数据以 hex 格式存储在平面文件中。他们提供了一个可以正常工作的odbc驱动程序,但是速度很慢。

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

基本上,此代码位于 webapi 中。它获取数据,用它制作一个 csv 和 return 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。

这个特定 table 的问题是有 150 列。处理所有这 150 列是一直需要的。

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

这是一个转折点!

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

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

感谢您的宝贵时间!

我找到了使 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 线程!