繁体   English   中英

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

[英]MS Access Batch Update via ADO.Net and COM Interoperability

这是这个帖子的后续行动。 这都是.Net 2.0 ; 对我来说,至少。

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

我想我只是想了解为什么 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)

无论如何,我觉得这很奇怪所以我尝试了几种同样的东西:

  • 切换OleDB for ODBC
  • 循环遍历数据表并为每一行运行INSERT语句
    • 无论如何,这就是.Update所做的
  • 使用ACE提供程序而不是Jet(ODBC和OleDB)
  • 从DataReader.Read循环中运行Data Adapter Update
    • 出于沮丧; 这很有趣。

最后,我尝试使用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

其他几点说明:

  • 在所有示例中,所有内容都转换为字符串,以尽可能保持简单和一致
    • 例外:在我的第一个例子中,使用Table.Load函数,我不是因为......好吧,我真的不能,但是当我通过阅读器循环并构建插入命令时,我做的基本相同(这是无论如何,它在做什么。 它没有帮助。
  • 对于每个领域......下一个对阵场(i)对阵场(名称)对我没有任何影响
  • 我运行的每个测试都是在新压缩的Access数据库中使用空的预构建数据表开始的
  • 将数据读取器加载到内存中的数据表大约需要3秒钟
  • 我不认为这是编组数据的问题,因为Marc的帖子表明通过自动化加载文本文件与DAO一样快 - 如果有的话,它不应该在使用ODBC / OleDB时编组数据,但它应该使用自动化时
  • 所有这些都让我感到困扰,因为它没有意义

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

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

DAO方法AddNewUpdate委托直接到MS Access等价物,它决不会生成SQL,因此MS Access无法解析SQL。

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

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

无论哪种方式,你的时间都会产生SQL,然后有一些东西解释SQL,DAO方法绕过SQL生成/解释并直接进入金属。

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

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

我知道这个问题已经过时了,但答案可能会帮助那些仍在努力解决这个问题的人。

还有另一种方法需要考虑。 由于源连接字符串和目标连接字符串都是已知的,源表可以链接到目标Access数据库,可能需要通过DAO或ADOX进行一些连接字符串解析(我知道,ADOX在这里是偏离主题的)。
通过在DAO或OleDb连接上向目标Access数据库发出这样的语句,可以相当快速地传输如此链接的表中的数据:

SELECT * INTO Table1 FROM _LINKED_Table1

一些缺点(请指出我错过的任何东西):

  • 源表必须包含主键
  • 必须通过检查源索引架构来重新创建主键和索引
  • 在查询运行时不容易获得传输进度状态

一些优点(请指出我错过的任何东西):

  • 如果要复制所有用户表,则只需要检查源表模式
  • 不必检查源Columns模式以生成CREATE TABLE语句的列定义
    (例如,尝试从OleDb模式中可靠地获取AUTONUMBER / IDENTITY信息,即不基于检查其他模式而对列值和标志位的组合进行假设)
  • 不必生成大量的INSERT INTO ... VALUES ...语句,在代码中考虑AUTONUMBER / IDENTITY列,或者为代码中的每一行运行数据库操作
  • 能够指定过滤转移记录的标准
  • 不必担心文本,日期或时间列或如何在查询中分隔,转义或格式化它们的值,除非在查询条件中使用

这种方法用于生产项目,至少对我来说是最快的。 :O)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM