【问题标题】:Access DAO Performance issue访问 DAO 性能问题
【发布时间】:2015-09-30 11:10:09
【问题描述】:

我正在使用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 到访问数据库的复制作业,因此它首先通过 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 读取显示没有差异,因此排除了问题的原因。

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

调用方法(运行器与控制台应用程序)中没有反射、泛型、不安全代码或隐藏的工件,可以解释这种行为,因为它们都只构建运行时参数并调用作业。我什至用 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 对象方面具有此类经验?

【问题讨论】:

  • 多少行? MSAccess db 文件是存储在本地还是网络上?还是使用 SQL Server 进行存储?
  • 这是一个本地访问硬盘的数据库,大约有 20 个表,行数变化很大,最大的可达 60k
  • 首先收集事实,使用分析器。
  • 我不知道分析器能够处理 xunit 测试。
  • 你在你的东西中使用反射吗?您是否尝试过使用控制台应用程序来运行调试版本(减去 xunit 的东西)?考虑一下您的控制台应用程序和您的 xunit 之间还有什么不同。听起来您的控制台应用程序可能是某种调用库的运行器,而您的 xunit 仅调用该库。很难说出与您的描述(上图)有何不同。

标签: c# ms-access-2010 dao


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-06-28
      • 2018-09-24
      • 1970-01-01
      • 2017-04-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多