优化 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 线程!
所以为了一个项目,我需要从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 线程!