C# 访问DAO性能问题

C# 访问DAO性能问题,c#,ms-access-2010,dao,C#,Ms Access 2010,Dao,我正在使用Microsoft.Office.Interop.Access.Dao.DBEngine将数据写入现有的accdb模板。这是由特定程序集中的特定类完成的 现在我观察到两种情况:当我在xunit(1.9.2和VS runner 2.0.1)测试中启动例程(调试构建),作为TE.ProcessHost.Managed.exe中的32位进程,它需要大约一分钟才能完成。以32位模式从控制台应用程序以发布版本的形式启动它需要超过12分钟。 我只是实例化了一个new DbEngine(),然后调用

我正在使用
Microsoft.Office.Interop.Access.Dao.DBEngine
将数据写入现有的
accdb
模板。这是由特定程序集中的特定类完成的

现在我观察到两种情况:当我在xunit(1.9.2和VS runner 2.0.1)测试中启动例程(调试构建),作为TE.ProcessHost.Managed.exe中的32位进程,它需要大约一分钟才能完成。以32位模式从控制台应用程序以发布版本的形式启动它需要超过12分钟。 我只是实例化了一个
new DbEngine()
,然后调用
OpenTable(name)
每个要填充的表和每个要插入的行的table.Update()(无更新,仅插入)。程序集引用了Microsoft.Office.interop.access.dao.dll版本15.0.4420.1017(access 2010)

我在寻找一条线索,从哪里开始挖掘这些巨大差异的原因

编辑: 基本上,它是从SQL Server到access db的复制作业,因此它首先通过ADO从SQL Server读取数据,然后将其插入accdb。像这样(不是确切的代码):

单元测试只是为复制作业创建参数,创建相关对象并启动作业。控制台应用程序也有同样的功能。分析、计时和调试总是导致
table.Update()
成为成本最高的调用。SQL读取没有显示任何差异,因此排除了问题的原因

这里询问的原因实际上是,我需要一个想法,在那里我可以进一步调查,因为代码本身没有显示明显的差异

调用方法(runner vs console app)中没有反射、泛型、不安全代码或隐藏的工件可以解释这种行为,因为它们都只生成运行时参数并调用作业。我甚至用char比较了这些参数。 所以我想知道,控制台应用程序和VS test runner之间是否存在“环境差异”,因为我在这里处理的是COM对象

更新2:

这些天来,我有时间再次调查这个问题。 所以我添加了计时测量来比较各个步骤。从SQL Server获取数据的时间也差不多。有趣的部分再次出现在这里:

foreach(var tableName in tables)
{
  readSqlIntoArray(tablename, tableData);
  var daoTable = daoDb.OpenTable(tableName);

  foreach(var row in tableData)
  {
    var rowArray = row.ItemArray;

    // because of type conversions this loop is necessary
    for (int i = 0; i < rowArray.Length; i++)
    {
        var srcValue = rowArray[i];
        if (srcValue.GetType() == typeof(TimeSpan))
        {
            // TimeSpan cannot be automatically converted and would cause exception
            tabl.Fields[i].Value = ((TimeSpan)srcValue).ToString(@"hh\:mm");
        }
        else if (srcValue.GetType() == typeof(Guid))
        {
            // Guid cannot be automatically converted and would cause exception
            // so wrap it as string
            tabl.Fields[i].Value = ((Guid)srcValue).ToString();
         }
         else
         {
             // even this assignment is taking longer in console app
             // than in testrunner (te.processhost.managed.exe)
             tabl.Fields[i].Value = srcValue;
         }
    }

    daoTable.Update();  
  }
}
foreach(表中的变量tableName)
{
readSqlIntoArray(tablename,tableData);
var daoTable=daoDb.OpenTable(tableName);
foreach(tableData中的var行)
{
var rowArray=row.ItemArray;
//由于类型转换,此循环是必需的
for(int i=0;i
表行字段的赋值行为似乎有所不同,尽管代码行完全相同。在调试器中,我看不到底层COM对象在测试和控制台中是否总是属于同一类型。
任何人在托管应用程序的COM对象中有这样的经验?

一种方法可能是利用MSAccess文件中的passthru查询从SQLServer检索数据,并使用insert查询将数据复制到本地访问表中。因为没有用户代码,所以很想知道是否存在性能差异。如果不是,则可能是外部问题,如磁盘IO、索引或网络问题(假设SQL Server位于另一台计算机上)。

在分析问题并询问COM对象时,我发现了简单而明确的原因:应用程序的单元状态。如果未设置为STA,COM对象需要复杂的编组,并将不正确的调用打包到代理中,这非常昂贵

[STAThread]
装饰控制台应用程序是唯一必要的。我猜,默认情况下,VisualStudio测试运行程序是单线程自动启动的,而普通应用程序不是。
COM及其与STA的亲和力是我一直在寻找的关键。

有多少行?MSAccess数据库文件是本地存储还是网络存储?或者它使用SQL Server存储?它是硬盘上的本地访问数据库,大约有20个表,行数变化很大,最大的表多达60Kg。首先,使用探查器。我不知道探查器能够处理xunit测试。你在你的东西中使用反射吗?您是否尝试过使用console应用程序运行调试构建(不包括xunit)?考虑一下你的控制台应用程序和XUnbe之间有什么不同。听起来你的控制台应用程序可能是某种调用lib的运行程序,而你的xunit只调用lib。很难说什么与你的描述(上面)不同。
foreach(var tableName in tables)
{
  readSqlIntoArray(tablename, tableData);
  var daoTable = daoDb.OpenTable(tableName);

  foreach(var row in tableData)
  {
    var rowArray = row.ItemArray;

    // because of type conversions this loop is necessary
    for (int i = 0; i < rowArray.Length; i++)
    {
        var srcValue = rowArray[i];
        if (srcValue.GetType() == typeof(TimeSpan))
        {
            // TimeSpan cannot be automatically converted and would cause exception
            tabl.Fields[i].Value = ((TimeSpan)srcValue).ToString(@"hh\:mm");
        }
        else if (srcValue.GetType() == typeof(Guid))
        {
            // Guid cannot be automatically converted and would cause exception
            // so wrap it as string
            tabl.Fields[i].Value = ((Guid)srcValue).ToString();
         }
         else
         {
             // even this assignment is taking longer in console app
             // than in testrunner (te.processhost.managed.exe)
             tabl.Fields[i].Value = srcValue;
         }
    }

    daoTable.Update();  
  }
}