Performance 使用ADO.NET/OleDb将非常慢的记录插入Jet数据库

Performance 使用ADO.NET/OleDb将非常慢的记录插入Jet数据库,performance,ado.net,oledb,jet,Performance,Ado.net,Oledb,Jet,我试图通过ADO.NET/OleDb将大量记录插入Jet(Access)数据库。它慢得令人痛苦。缓慢主要是由于方法。用微软的话说 …这些语句不是作为批处理执行的;每一行都会单独更新 这是一个真正的WTF,因为我的数据库应用程序提供的性能比使用旧ADO或DAO(带有AddNew/Update循环的记录集)的VB6中的等效代码慢约30倍 SqlClient提供程序具有类;OleDb有什么等价物吗 即使能够更改其写缓存行为也可能有所帮助。(即,插入每一行后不要刷新缓存!) 有什么我可以做的吗,或者AD

我试图通过ADO.NET/OleDb将大量记录插入Jet(Access)数据库。它慢得令人痛苦。缓慢主要是由于方法。用微软的话说

…这些语句不是作为批处理执行的;每一行都会单独更新

这是一个真正的WTF,因为我的数据库应用程序提供的性能比使用旧ADO或DAO(带有
AddNew
/
Update
循环的记录集)的VB6中的等效代码慢约30倍

SqlClient提供程序具有类;OleDb有什么等价物吗

即使能够更改其写缓存行为也可能有所帮助。(即,插入每一行后不要刷新缓存!)

有什么我可以做的吗,或者ADO.NET只是为了Jet而被破坏了

*编辑添加:这是我的代码的精简版本,使用精简测试数据库

首先是VBA/ADO版本(Access 2003):

输出:
添加10000的时间(通过ADO)0.296875

现在是ADO.NET版本(VB.NET 2010):


输出:
添加10000的时间(通过ADO.NET):5.859375

确保调用该方法时连接已打开。如果在调用update方法之前关闭了连接(我在一些示例代码中看到了这一点),那么update方法可能会尝试以非最佳方式打开连接。
如果连接未合并,Jet中打开连接的速度可能非常慢。您可能需要添加OLE DB SERVICES=-1以确保连接是池连接。

您真的要用随机值填充表吗?如果是这样,则有更快的方法(使用基于现有表或附加到的表的插入,以便可以多次运行它并快速达到所需的记录数)

通常,SQL插入要比一次添加一条记录快一个数量级。如果必须按当前的方式执行,则可以通过ADO/ADO.NET查看是否可以使用Jet/ACE事务。我一点也不知道这是否可行。如果不是,假设COM是一个选项,你应该考虑只使用DAO,这样你就可以使用JECT/ACE事务,这会延迟写到最后(比如发布一个批)。

我不是ADO Maven,但我在经典ADO中也有一些批处理功能,所以你也可以考虑调查这个问题。

建议你发布删减代码…@米奇麦克:好的,我把它添加到这个问题中。你试过使用一个交易吗?我已经发布了代码。这能说明你的观点吗?另外,我不确定“OLE DB SERVICES=-1”是什么意思?我支持这个答案,因为我刚刚遇到了这个问题。有时,您可以通过观察.ldb文件在每个连接打开和关闭之间的显示和消失来验证是否启用了连接池。当然,随机值仅用于说明-实际数据是以编程方式以其他表作为输入生成的。至于使用DAO或ADO,我希望坚持使用.NET中内置的内容。我希望ADO.NET中也会有批插入,但我只是猜测,因为像我这样的Access开发人员没有任何调用。如果数据值来自其他表,为什么每次插入一条记录?为什么不使用SELECT作为SQL插入的值源?这是一个指向stackoverflow问题的链接,让它留在这里。
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
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()