2013-04-03 51 views
6

这是this thread的后续行为。这全是用.Net 2.0;至少对我来说。从本质上讲,马克(从上面的OP)尝试了几种不同的方法来更新一个有100000条记录的MS Access表,发现使用DAO连接大概是比使用ADO.Net快了10-30倍。我走下了几乎相同的路径(下面的例子),并得出了同样的结论。通过ADO.Net和COM互操作性的MS Access批量更新

我想我只是想了解为什么 OLEDB和ODBC是如此慢得多,我很想听听如果有人在2011年发现了比DAO一个更好的答案,因为这个职位,我真的很宁愿避免DAO和/或自动化,因为他们要求客户端机器具有Access或数据库引擎的可再分发(或者我被DAO 3.6支持,不支持.ACCDB)。

最初尝试; 〜100秒10万条记录/ 10列:

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对ODBC
  • 环流式通过数据表和运行的INSERT语句的每一行
    • 这是.Update确实反正
  • 使用ACE提供商代替射流(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 

其他一些注意事项:

  • 一切都转换为字符串在所有的例子,试图让事情变得简单,并尽可能
    • 异常一致:在我的第一个例子中,使用Table.Load函数,我不是因为......嗯,我真的不行,但是当我通过阅读器并构建插入命令(正是它在做什么)时,我做了基本相同的事情。它没有帮助。
  • For Each Field ... Next vs. Field(i)vs.字段(名称)没有什么区别,我
  • 每次我在刚压缩Access数据库
  • 加载数据读取到数据表中的内存跑开始与空,预先建立数据表检验需要2-3秒
  • 我不认为这是编组数据的问题,因为Marc的帖子指出通过Automation加载文本文件的速度与DAO一样快 - 如果有的话,在使用ODBC/OleDB时不应该封送数据,但它应该当使用自动化
  • 所有这些困扰我的方式超过它应该,因为它没有意义

希望有人能够阐明这一点......这很奇怪。 在此先感谢!

回答

4

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

DAO方法AddNewUpdate直接委托给MS Access等价物,它在任何时候都不会生成SQL,所以没有SQL可以被MS Access解析。

在另一方面,DataAdapter的代码生成一个Update语句对于每一行,该更新语句被传递给ODBC,然后通过这一个MSACCESS驱动程序,或者

  1. 独立分析SQL和问题AddNewUpdate 命令到数据库或
  2. 传递SQL到MS Access,这是不解析SQL, 优化,并且其一旦被解析,结束平移SQL成AddNewUpdate命令。

无论哪种方式,您都需要花时间生成SQL,然后让某些东西解释SQL,其中DAO方法绕过SQL生成/解释并直接转换为金属。

解决这个问题的一种方法是使用access db在机器上创建自己的“数据库服务”。这汇集您的选择&更新,并可以通过远程处理,WCF(http或其他)与客户端进行通信。这是很多工作,并且相当大地改变了您的应用程序逻辑。

数据库驱动程序搞清楚正确的名称(例如喷气或其他)是留给读者

+0

感谢您的解释!我知道DAO直接坐落在数据库引擎上,我从来没有见过*只是使用一个额外的中间件层而导致性能急剧下降。在这种情况下,与其他DBMS相比,Access的主要目标是更新通常是否会批量运行更新,而不是通过ODBC传递每条记录? – Karter

+0

命中**是因为它是Access。它不会像(火焰诱饵在这里)_real_ RDBMS一样糟糕,对于SQL Server(和SQL Server express),您也可以使用'SqlBulkCopy'类以接近表面融化速度插入行。如果可以的话,我会诚实地推荐MS Access并开始使用SQL Express运行。我广泛地在当天使用Access,并且从不喜欢它。 _“啧啧,我很高兴我使用了该项目的访问权限”,表示没有人曾经_ –

+1

我不反对;但是,你知道,**遗产支持所有的事情** – Karter

2

我知道这个问题是旧的,但答案可能帮助别人还在为此努力的练习。

还有另一种方法要考虑。由于源连接字符串和目标连接字符串都是已知的,因此可以通过DAO或ADOX(我知道ADOX在这里是脱离主题)将源表链接到目标Access数据库,可能需要一些连接字符串解析。

SELECT * INTO Table1 FROM _LINKED_Table1 

一些缺陷(请指出什么我错过了):
在这样的链接表的数据可以很快地通过发出下面的语句在DAO或OLEDB连接到目标Access数据库转移

  • 源表必须包含一个主键
  • 主键和索引都通过检查源索引架构中重新创建
  • 不容易得到传输进度小号tatus而查询正在运行

一些优点(请指出什么我错过了):

  • 只具有检查源表的模式,如果所有用户表将被复制
  • 不有检查源列的架构生成列定义的CREATE TABLE语句
    (例如,尝试基于检查其他模式获得自动编号/身份信息可靠出一个OLEDB模式,即无需假设有关标志位的列值的组合)
  • 不需要生成大量的INSERT INTO ... VALUES ...语句,占用代码中的AUTONUMBER/IDENTITY列,或者以其他方式运行数据库操作,以便代码中的每一行可以指定
  • 标准过滤器转移记录
  • 不具有查询条件使用时不用担心文本,日期或时间列或如何限定,逸出或除了在查询格式化它们的值

在生产中使用这种方法项目,结果是最快的,对我来说至少。 :o)