访问DAO性能问题

时间:2015-09-30 11:10:10

标签: c# ms-access-2010 dao

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

现在我正在观察两种情况:当我在xunit(带有VS runner 2.0.1的1.9.2)中开始我的例行程序(调试构建)测试作为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到访问数据库的复制作业,因此它首先通过ADO从SQL-Server读取数据,然后将其插入到accdb中。像这样(不是确切的代码):

foreach(var tableName in tables)
{
  readSqlIntoArray(tablename, tableData);
  var daoTable = daoDb.OpenTable(tableName);
  foreach(var row in tableData)
  {
    // ... add new record and copy data

    daoTable.Update();  // this is the expensive call in console app
  }
}

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

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

调用方法(runner vs console app)中没有反射,泛型,不安全的代码或隐藏的工件,这可以解释这种行为,因为它们都只构建运行时参数并调用作业。我甚至用char比较了这些参数。 所以我想知道,如果控制台应用程序和VS测试运行器之间存在一些“环境差异”,因为我在这里处理一个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();  
  }
}

看起来,表行字段的赋值似乎表现不同,尽管它们的代码行完全相同。在调试器中我无法看到,如果底层COM对象在测试和控制台中始终是相同的类型。 在托管应用程序中具有COM对象经验的任何人?

2 个答案:

答案 0 :(得分:0)

一种方法可能是利用MSAccess文件中的passthru查询从SQLServer检索数据,并使用插入查询将数据复制到本地访问表中。由于没有用户代码,因此很难看出是否存在性能差异。如果没有,那么它可能是一个外部问题,如磁盘IO,索引或网络问题(假设SQL Server在另一台计算机上)。

答案 1 :(得分:0)

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

使用class ProjectSerializer(CoreHyperlinkedModelSerializer): client = serializers.SerializerMethodField() def get_client(self, obj): serializer = ClientSerializer(obj.client.objects.all()) return serializer.data class Meta: model = Task fields = ('url', 'id', 'name', 'client', ) 装饰控制台应用程序是唯一必要的。我猜,默认情况下,visual studio测试运行器会自动启动单线程,而普通应用程序则不会。 COM及其对STA的亲和力是我一直在寻找的关键。