очень медленная вставка записи в базу данных Jet с использованием ADO.NET / OleDb - PullRequest
0 голосов
/ 27 декабря 2010

Я пытаюсь вставить много записей в базу данных Jet (Access) через ADO.NET / OleDb.Работает мучительно медленно.Медлительность в основном связана с методом DbDataAdapter.Update.По словам Microsoft,

... эти операторы не выполняются как пакетный процесс;каждая строка обновляется индивидуально.

Это настоящий WTF, поскольку моя база данных дает производительность примерно в 30 раз медленнее, чем эквивалентный код в VB6, использующий старый ADO или DAO (набор записей с AddNew /Update loop).

Поставщик SqlClient имеет класс SqlBulkCopy;Есть ли что-нибудь эквивалентное для OleDb?

Даже возможность изменить поведение кэширования записи может помочь.(т.е. не очищайте кеш после вставки каждой строки!)

Могу ли я что-нибудь сделать, или ADO.NET просто не работает для Jet?

* Отредактировано: Вот урезанная версия моего кода с использованием урезанной тестовой базы данных.

Во-первых, версия VBA / ADO (Access 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 (VB.NET 2010):

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

Ответы [ 3 ]

1 голос
/ 27 декабря 2010

Убедитесь, что соединение открыто при вызове метода. Если соединение закрывается до вызова метода обновления (я действительно видел это в некотором примере кода), метод обновления может попытаться открыть соединение неоптимальным способом. Открытие соединений в Jet может быть очень медленным, если соединение не объединено в пул. Возможно, вам потребуется добавить OLE DB SERVICES = -1, чтобы убедиться, что соединение находится в пуле.

0 голосов
/ 28 декабря 2010

Вы действительно пытаетесь заполнить таблицу случайными значениями?Если это так, есть более быстрые способы сделать это (используя INSERT на основе существующей таблицы или таблицы, к которой вы добавляете, чтобы вы могли запустить ее несколько раз и быстро достичь нужного количества записей).

Как правило, SQL INSERT будет на порядок быстрее, чем добавление одной записи за раз.Если вам нужно сделать это так, как вы это делаете, вы можете посмотреть, можете ли вы использовать транзакцию Jet / ACE через ADO / ADO.NET.Я понятия не имею, доступно это или нет.Если это не так и предполагается, что COM является опцией, вам следует рассмотреть возможность использования DAO, чтобы можно было использовать транзакции Jet / ACE, которые задержат запись до самого конца (например, отправка пакета).

I 'm no ADO maven, но я вспоминаю, что в Classic ADO тоже есть некоторые пакетные функции, так что вы можете рассмотреть и это.

0 голосов
/ 27 декабря 2010
...