9

これは、このスレッドのフォローアップのようなものです。これはすべて.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 が行うことです
  • Jet (ODBC および OleDB) の代わりに ACE プロバイダーを使用する
  • 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. Field(name) は私にとって違いはありませんでした
  • 私が実行したすべてのテストは、新しく圧縮された Access データベース内の事前構築済みの空のデータ テーブルから開始されました。
  • データ リーダーをメモリ内のデータ テーブルにロードするのに約 3 秒かかります
  • データのマーシャリングに問題があるとは思いません。なぜなら、Marc の投稿では、オートメーションによるテキスト ファイルの読み込みは DAO と同じくらい高速であることが示されているからです自動化を使用する場合
  • 意味をなさないので、これらすべてが必要以上に私を悩ませます

うまくいけば、誰かがこれに光を当てることができるでしょう...それはただ奇妙です. 前もって感謝します!

4

2 に答える 2

2

この質問は古いことは知っていますが、答えはまだこれに苦しんでいる人を助けるかもしれません.

考慮すべき別の方法があります。ソース接続文字列とターゲット接続文字列の両方が既知であるため、DAO または ADOX を介してソース テーブルをターゲット Access データベースにリンクできます。接続文字列の解析が必要になる場合があります (ADOX はここではトピック外です)。
このようにリンクされたテーブルのデータは、ターゲット Access データベースへの DAO または OleDb 接続で次のようなステートメントを発行することにより、かなり迅速に転送できます。

SELECT * INTO Table1 FROM _LINKED_Table1

いくつかの欠点(私が見逃したものを指摘してください):

  • ソース テーブルには主キーが含まれている必要があります
  • ソース インデックス スキーマを調べて、主キーとインデックスを再作成する必要があります。
  • クエリの実行中に転送の進行状況を簡単に取得できない

いくつかの利点(私が見逃したものを指摘してください):

  • すべてのユーザー テーブルをコピーする場合は、ソース テーブル スキーマを調べるだけで済みます
  • CREATE TABLE ステートメントの列定義を生成するためにソースの列スキーマを調べる必要がない
    (たとえば、他のスキーマの調査に基づいて列値とフラグ ビットの組み合わせに関する仮定なしで、OleDb スキーマから AUTONUMBER / IDENTITY 情報を確実に取得してみてください) )
  • 膨大な量の INSERT INTO ... VALUES ... ステートメントを生成する必要がなく、コード内の AUTONUMBER / IDENTITY 列を考慮したり、コード内の各行に対してデータベース操作を実行したりする必要はありません
  • 転送されたレコードをフィルタリングする基準を指定できる
  • クエリ条件で使用される場合を除いて、テキスト、日付、または時刻の列、またはクエリでそれらの値を区切り、エスケープ、またはフォーマットする方法について心配する必要はありません

この方法は生産プロジェクトで採用され、少なくとも私にとっては最速であることが判明しました。:o)

于 2014-10-09T20:19:08.090 に答える