2013-04-03 79 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)