2010-12-27 75 views
0

ADO.NET/OleDb経由でJet(Access)データベースに多数のレコードを挿入しようとしています。それはゆっくりと痛みを伴う。遅さは、主にDbDataAdapter.Updateメソッドによるものです。 Microsoftの言葉では、ADO.NET/OleDbを使用してJetデータベースに非常に遅いレコードが挿入される

...これらのステートメントはバッチ処理として実行されません。各行は個別に更新されます。

私のデータベースアプリケーションが古いADOやDAO(AddNew/Updateループ付きレコード)を使用してVB6での同等のコードよりも約30倍遅くパフォーマンスを提供しますので、これは本当のWTFです。

SqlClientプロバイダーには、SqlBulkCopyクラスがあります。 OleDbに相当するものはありますか?

書き込みキャッシングの動作を変更することもできます。 (つまり、各行が挿入された後でキャッシュをフラッシュしないでください)

私はできることは何ですか、またはADO.NETはJetのために壊れていますか?

* 編集済み:ここでは、カットダウンテストデータベースを使用して、私のコードをカットダウンしたバージョンです。

まず、VBA/ADOのバージョン(アクセス2003):

Dim con As ADODB.Connection 
Set con = CurrentProject.Connection 
con.Execute "DELETE * FROM tblTest", , adCmdText Or adExecuteNoRecords 
Dim rs As ADODB.Recordset 
Set rs = New ADODB.Recordset 
rs.Open "tblTest", con, , adLockPessimistic 
Dim i&, t! 
t = Timer 
For i = 1 To 10000 
    rs.AddNew 
    rs!mainKey = i 
    rs!testColumn = Rnd * 100 
    rs.Update 
Next 
rs.Close 
Debug.Print "time to add 10000 (by ADO) " & Timer - t 

出力:time to add 10000 (by ADO) 0.296875

今ADO.NETのバージョン(2010 VB.NET):

Dim sProvider As String = "PROVIDER = Microsoft.Jet.OLEDB.4.0;" 
Dim sDataSource As String = "Data Source = 'C:\test.mdb'" 
Dim connection As New OleDbConnection(sProvider & sDataSource) 
connection.Open() 
Dim q As New OleDbCommand("DELETE * FROM tblTest", connection) 
q.ExecuteNonQuery() 
Dim ds As New DataSet 
Dim selectCmd As OleDbCommand = connection.CreateCommand() 
selectCmd.CommandText = "SELECT * FROM tblTest" 
Dim da As New OleDbDataAdapter(selectCmd) 
da.Fill(ds, "tblTest") 
Dim theTable As DataTable = ds.Tables("tblTest") 
For i As Integer = 1 To 10000 
    Dim row = theTable.NewRow() 
    row.Item("mainKey") = i 
    row.Item("testColumn") = Rnd() * 100 
    theTable.Rows.Add(row) 
Next i 
Dim t! : t = Microsoft.VisualBasic.Timer 
Dim cb As New OleDbCommandBuilder(da) 
da.Update(ds, "tblTest") 
Debug.Print("time to add 10000 (by ADO.NET): " & Microsoft.VisualBasic.Timer - t) 
connection.Close() 

出力:time to add 10000 (by ADO.NET): 5.859375

+1

あなたがカットダウンコードを投稿することをお勧めします。 –

+0

@Mitch Wheat:OK質問に追加しました。 –

+0

トランザクションを使用しようとしましたか? – FrinkTheBrave

答えて

1

メソッドがcaのときに接続が開いていることを確認します。だまされた。更新メソッドが呼び出される前に接続が閉じられていると(私は実際にコード例でそれを見た)、更新メソッドは最適でない方法で接続を開こうと試みる可能性があります。 接続がプールされていないと、Jetで接続を開くのが非常に遅くなる可能性があります。接続がプールされていることを確認するには、OLE DB SERVICES = -1を追加する必要があります。

+0

私はコードを投稿しました。それはあなたのポイントに対処していますか?また、私はあなたが "OLE DB SERVICES = -1"の意味を理解していませんか? –

+0

私はちょうどこの問題に遭遇したので、私はこの答えを秒です。接続のプーリングが有効になっているかどうかは、.ldbファイルが開いているか閉じているかの間に現れ、消えるのを見て確認できます。 – MatthewMartin

0

あなたは本当にランダムな値を持つテーブルを移入しようとしていますか?そうであれば、既存のテーブルや追加するテーブルに基づいてINSERTを使用するより高速な方法があるため、複数回実行して必要なレコード数にすばやくアクセスできます。

一般に、SQL INSERTは、一度に1つのレコードを追加するよりもはるかに高速です。あなたがそれをやっているようにしなければならない場合は、ADO/ADO.NETを介してJet/ACEトランザクションを使用できるかどうかを調べることができます。私は利用可能かどうかの手掛かりはありません。そうでなければ、COMがオプションであると仮定して、Jet/ACEトランザクションを使用できるようにDAOだけを考慮する必要があります。これは、バッチをポストするような書き込みを最後まで遅延させます。

私はADO mavenではありませんが、クラシックADOにはいくつかのバッチ関数がありますので、そのことについても検討することをおすすめします。

+0

ランダム値はもちろん説明のためのものです。実際のデータは他のテーブルを入力としてプログラムによって生成されます。 DAOやADOの使用に関しては、.NETに組み込まれているものに固執したいと考えていました。 –

+0

私はADO.NETにバッチインサートがあることを期待していますが、自分自身のようなAccess開発者が使用する呼び出しがないので、推測しています。 –

+1

データ値が他のテーブルから派生している場合、一度に1つのレコードを挿入するのはなぜですか?なぜSQL INSERTの値のソースとしてSELECTを使用しないのですか? –

関連する問題