VB6 Ms Access редактирование базы данных большое количество записей

Мне нужно обработать сотни тысяч записей с помощью VB6 и базы данных MS Access. Я перебираю набор записей и редактирую каждую запись. Однако для этого требуется много времени. Создание базы данных с одинаковым количеством записей с помощью методов Addnew и Update работает намного быстрее.

Я буду очень признателен, если кто-нибудь покажет мне образец кода или просто стратегию.

здесь код

Data1(1).RecordSource = "Select * from TABLE order by Field_A ASC"
Data1(1).Refresh
If Data1(1).Recordset.RecordCount > 0 Then
    Data1(1).Recordset.MoveFirst
    Do
        Data1(1).Recordset.Edit
        Data1(1).Recordset.Fields("FIELD") = Sort_Value
        Data1(1).Recordset.Update
        Data1(1).Recordset.MoveNext
    Loop Until Data1(1).Recordset.EOF = True
End If

Это действительно довольно просто. Этот реальная вещь, я забыл упомянуть, что Tha HDD компьютера постоянно краснеет/пишет. В этом-то и проблема. При такой большой нагрузке невозможно не повлиять на производительность.

Я сначала подумал, что набор записей, сгенерированный запросом, имейте в виду, что мы имеем 1-2 миллиона записей, вызывает эту проблему. Я думаю, он находится на каком-то временном месте на жестком диске и в ОЗУ. И так казните .Редактировать и. Обновление может быть проблемой при первом позиционировании курсора на в нужном месте, а потом писать.

Не знаю точно. Возможно, найдется эксперт, который покажет мне выход.

кстати. Я также попытался заменить Цикл До Data1 (1).Набор записей.ВФ = истина оператор с циклом фиксированной длины, потому что я также читал, что это проверка набора записей.EOF также замедляет производительность.

спасибо заранее!

4 ответов


Я создал таблицу с названием test с полями n и f(n)

Timed 3 различные подпрограммы обновления - записей без операции - набор записей с транзакцией - обновить запрос

Sub updateFunction_noTrans()
    Dim rs As Recordset
    Set rs = CurrentDb.OpenRecordset("test")
    rs.MoveFirst
    Do Until rs.EOF
        rs.Edit
        rs("f(n)") = rs("n") + 1
        rs.Update
        rs.MoveNext
    Loop
End Sub

это в основном то, что вы делаете, прямой набор записей при редактировании поля

Sub updateFunction_yesTrans()
    Dim i As Long
    Dim commitSize As Long
    Dim rs As Recordset
    commitSize = 5000
    Set rs = CurrentDb.OpenRecordset("test")
    DBEngine.Workspaces(0).BeginTrans
    rs.MoveFirst
    Do Until rs.EOF
        rs.Edit
        rs("f(n)") = rs("n") + 1
        rs.Update
        rs.MoveNext
        i = i + 1
        If i = commitSize Then
            DBEngine.Workspaces(0).CommitTrans
            DBEngine.Workspaces(0).BeginTrans
            i = 0
        End If
    Loop
    DBEngine.Workspaces(0).CommitTrans
End Sub

это та же идея, но с транзакциями. Я фиксирую 5000 записей за раз, поскольку был установлен некоторый предел около 9k-10k за фиксацию. Вы можете отредактируйте это, я считаю, войдя в реестр.

Sub updateFunction_updateQuery()
    CurrentDb.Execute ("UPDATE test SET test.[f(n)] = [n]+1;")
End Sub

это быстрее, чем любой из методов набора записей. Например. на около 2 миллионов записей потребовалось ~20 секунд без транзакций, ~18-19 секунд с транзакциями, ~14 секунд с запросом обновления.

это все в предположении, что поле, которое будет обновляться, зависит от значений, вычисленных от других дьяволов в этих записях

чтобы действительно ускорить такие действия, иногда это в зависимости от ситуации и более подробной информации, если это не применяется.

Edit: используется старая машина core 2 duo + нет индексов на полях


мое единственное предложение, которое может не работать в вашем случае, это сделать массовое обновление с помощью запроса на обновление.

три случая, когда это может сработать:

Если Sort_Value можно вычислить из других полей, это простой запрос обновления, но я уверен, что вы уже видели это.

Если Sort_Value можно вычислить из других записей (например, предыдущей записи), то вы, вероятно, можете написать более сложный запрос обновления (у меня видел несколько довольно сложных запросов, размещенных здесь).

наконец, если тот же Sort_Value применяется ко многим записям, затем вы можете выполнить запрос на обновление на основе этих записей. Итак, если Sort_Value может быть 10 различных значений, тогда все ваши обновления будут выполняться в 10 запросах обновления.


Если вы скажете нам, где вы получаете Sort_Value, мы могли бы быть в состоянии помочь вам дальше.


вот вещи, которые НЕ работа, чтобы ускорить команды редактирования / обновления, в соответствии с моим тестированием. Все это было сделано с использованием таблицы из 10 000 записей с 1 000 000 обновлений.

  • RS (1) вместо RS ("имя"). Это было предложено на другом сайте и на самом деле увеличение времени на 20%. (+25 сек / 21 сек)
  • BeginTrans/метод committrans сделал никакой разницы на ООН-индексированные поля, и был на 1% быстрее в индексированном поле. (un-indexed: 11 sec [w / trans] / 11 сек, индексируется: 23 сек [w / trans] / 25 сек)*
  • отдельные операторы SQL. (86 сек.)
  • параметр querydef. (43 сек)

*исправлены результат.


код для теста BeginTrans/CommitTrans.

Sub CommitTest()
   Dim C As String
   Dim I As Long
   Dim J As Long
   Dim RS As Recordset
   Dim BegTime As Date
   Dim EndTime As Date
   BegTime = Now()
   Set RS = CurrentDb.OpenRecordset("tblTest")
   For J = 1 To 200
      RS.MoveFirst
      DBEngine.Workspaces(0).BeginTrans
      For I = 1 To 5000
         C = Chr(Int(Rnd() * 26 + 66))
         RS.Edit
         RS("coltest") = C
         RS.Update
         RS.MoveNext
      Next I
      DBEngine.Workspaces(0).CommitTrans
   Next J
   EndTime = Now()
   Debug.Print DateDiff("s", BegTime, EndTime)
End Sub

хотя это может быть необходимо в некоторых случаях, итерации через наборы записей для обновления поля следует избегать.

разумной вещью, которая намного эффективнее, было бы написать запрос на обновление SQL.

Если ваша таблица настолько велика, вы должны быть осторожны с выбором ваших индексов, особенно первичного ключа.

затем вы можете разделить данные на основе вашего ПК и обновить все записи в первом наборе, а затем во втором, третий...

 UPDATE super_big_table
 SET Field_A = some_function_to_make_it_sort_value
 WHERE myPrimaryKey BETWEEN ( left_boundary AND right_boundary )

вы повторяете этот (по коду) для всех подразделений, которые вы сделали в таблице.

теперь вопрос в том, Можете ли вы придумать функцию доступа, которая создает требуемый Sort_value?

обратите внимание, что если Field_A является вашим первичным ключом, вы не должны его менять. В противном случае вся ваша таблица будет переставляться каждый раз, когда вы обновляете несколько записей, что будет большой работой для вашего HD / процессора. В этом случае у вас должен быть другой PK, и создайте индекс на Field_A, а не PK.


для повышения производительности вы можете использовать UpdateBatch метод объекта ADODB. Но для использования этой функции требуется:

  1. adOpenStatic cursorType и
  2. adLockBatchOptimistic LockType

для объекта recordset.
Кроме того, вы также можете использовать adUseClient CursorLocation для загрузки на клиент вместо сервера во время операции.

чтобы пойти дальше, воздержитесь от использования