.net - 通过 ADO.Net 和 COM 互操作性进行 MS Access 批量更新

标签 .net performance ms-access ado.net dao

这是对 this thread 的跟进。 .这就是 .Net 2.0 ;至少对我来说。

本质上,Marc(上面的 OP)尝试了几种不同的方法来更新具有 100,000 条记录的 MS Access 表,并发现使用 DAO 连接大致为 。快 10 - 30 倍 比使用 ADO.Net。我走了几乎相同的路径(下面的示例)并得出了相同的结论。

我想我只是想了解为什么 OleDB 和 ODBC 的速度要慢得多,我很想知道自 2011 年那篇文章以来是否有人找到比 DAO 更好的答案。我真的更愿意避免 DAO 和/或自动化,因为它们需要客户端机器具有 Access 或可再分发的数据库引擎(或者我坚持使用不支持 .ACCDB 的 DAO 3.6)。

最初的尝试; 100,000 条记录/10 列约 100 秒:

Dim accessDB As New OleDb.OleDbConnection( _ 
                      "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _
                                accessPath & ";Persist Security Info=True;")
accessDB.Open()

Dim accessCommand As OleDb.OleDbCommand = accessDB.CreateCommand
Dim accessDataAdapter As New OleDb.OleDbDataAdapter( _
                                   "SELECT * FROM " & tableName, accessDB)
Dim accessCommandBuilder As New OleDb.OleDbCommandBuilder(accessDataAdapter)

Dim accessDataTable As New DataTable
accessDataTable.Load(_Reader, System.Data.LoadOption.Upsert)

//This command is what takes 99% of the runtime; loops through each row and runs 
//the update command that is built by the command builder. The problem seems to 
//be that you can't change the UpdateBatchSize property with MS Access
accessDataAdapter.Update(accessDataTable)

无论如何,我觉得这真的很奇怪,所以我尝试了几种相同的口味:
  • 为 ODBC 切换 OleDB
  • 循环遍历数据表并为每一行运行一个 INSERT 语句
  • 这就是 .Update 的作用
  • 使用 ACE 提供程序而不是 Jet(ODBC 和 OleDB)
  • 从 DataReader.Read 循环中运行数据适配器更新
  • 出于沮丧;这很有趣。

  • 最后,我尝试使用 DAO。代码基本上应该做同样的事情;但显然不是,因为它在大约 10 秒内运行。
     Dim dbEngine As New DAO.DBEngine
     Dim accessDB As DAO.Database = dbEngine.OpenDatabase(accessPath)
     Dim accessTable As DAO.Recordset = accessDB.OpenRecordset(tableName)
    
    While _Reader.Read
        accessTable.AddNew()
          For i = 0 To _Reader.FieldCount - 1
            accessTable.Fields(i).Value = _Reader.Item(i).ToString
          Next
        accessTable.Update()
    End While
    

    其他一些注意事项:
  • 在所有示例中,所有内容都转换为字符串,以尽量保持简单和一致
  • 异常(exception):在我的第一个示例中,使用 Table.Load 函数,我不这样做是因为......好吧,我真的不能,但是当我遍历阅读器并构建插入命令时,我做了基本相同的事情(即无论如何,它在做什么)。它没有帮助。
  • 对于每个字段... Next vs. Field(i) vs. Field(name) 对我来说没有区别
  • 我运行的每个测试都从一个新压缩的 Access 数据库中的空的预构建数据表开始
  • 将数据读取器加载到内存中的数据表大约需要 3 秒
  • 我认为编码(marshal)数据不是问题,因为 Marc 的帖子表明通过自动化加载文本文件与 DAO 一样快——如果有的话,它不应该在使用 ODBC/OleDB 时编码(marshal)数据,但应该使用自动化时
  • 所有这一切都让我感到不安,因为它没有意义

  • 希望有人能够对此有所了解……这很奇怪。
    提前致谢!

    最佳答案

    这里的原因是 DAO 驱动程序比 ODBC 驱动程序更接近 MS Access 数据库引擎。

    DAO 方法 AddNewUpdate直接委托(delegate)给 MS Access 等效项,它在任何时候都不会生成 SQL,因此 MS Access 没有要解析的 SQL。

    另一方面,DataAdapter 代码为每一行生成一个更新语句,该更新语句被传递给 ODBC,然后由它传递给 MSAccess 驱动程序,该驱动程序要么

  • 独立解析 SQL 并发出 AddNewUpdateAccess 数据库或
  • 的命令
  • 将 SQL 传递给未针对解析 SQL 进行优化的 MS Access,
    并且一旦解析,最终将 SQL 转换为 AddNewUpdate命令。

  • 无论哪种方式,您都需要花费时间生成 SQL,然后让一些东西解释该 SQL,其中 DAO 方法绕过 SQL 生成/解释并直接进入金属。

    解决此问题的一种方法是创建您自己的“数据库服务”,该服务在具有 Access 数据库的机器上运行。这会编码您的选择和更新,并可以通过远程处理、WCF(http 或其他)与客户端进行通信。这是很多工作,并且会极大地改变您的应用程序逻辑。

    找出数据库驱动程序的正确名称(例如 Jet 或其他)是留给读者的练习

    关于.net - 通过 ADO.Net 和 COM 互操作性进行 MS Access 批量更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15788441/

    相关文章:

    .net - .NET 中的跨进程读写同步原语?

    c# - String.ToLower() 总是分配内存吗?

    vba - 失去与SharePoint问题的连接

    sql - MS Access SQL DELETE - 为什么有人会指定列名?

    python - 分析标签集的最佳方法?

    c# - 使用 C# 时我的属性出现问题

    .NET - TextWriterTraceListener,另一个进程正在使用的文件

    mongodb - 通过迁移到 NoSQL 提高速度

    sql - SQL 中的稀疏点积

    html - 在 HTML 中内联 CSS 以提高页面速度