Массовая вставка записей в Access с использованием Vbscript - PullRequest
4 голосов
/ 04 июля 2011

Я действительно тяну свои волосы с этим. У меня есть VBScript, и я пытаюсь вставить несколько сотен тысяч записей в базу данных Access.

Очевидно, что это очень медленно, если я делаю их по одному, поэтому я подумал, что смогу массово вставить их с какой-то транзакцией. Поэтому я попытался написать это:

set rs = CreateObject("ADODB.recordset")
 rs.Open "table", objConn,, 4

For counter = 1 to 100000
  rs.AddNew
  rs("username") = "Value"
Next

  rs.UpdateBatch

(objConn - это соединение с базой данных).

Проблема в том, что я получаю сообщение об ошибке:

"Количество строк с ожидающими изменениями превысило предел"

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

Полагаю, я неправильно настроил транзакцию, но я немного застрял. Не думаю, что кто-то может указать на ошибку моих путей? Большое спасибо.

Ответы [ 2 ]

9 голосов
/ 05 июля 2011

Чтобы отстаивать свое предложение использовать команду в транзакции, я написал такой скрипт:

  Dim sAct      : sAct      = "trout"
  If goWAN.Exists( "a" ) Then sAct = goWAN( "a" )
  Dim nRecs     : nRecs     = 10
  If goWAN.Exists( "n" ) Then nRecs = CLng( goWAN( "n" ) )
  Dim sMFSpec   : sMFSpec   = goFS.GetAbsolutePathName( "..\data\ut.mdb" )
  Dim oConn     : Set oConn = CreateObject( "ADODB.Connection" )
  Dim oRs       : Set oRs   = CreateObject( "ADODB.Recordset" )

  Dim nRec, oCmd, nRA, aData, oParm

  oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & sMFSpec
  Set oRs.ActiveConnection = oConn

  oConn.Execute( "DELETE FROM tLines" )
  WScript.Echo "#Recs:", oConn.Execute( "SELECT COUNT(SampleText) FROM tLines" ).Fields( 0 )

  WScript.Echo sAct
  Select Case sAct
    Case "trout"
    Case "bob"
      oRs.CursorLocation = adUseClient
      oRs.CursorType = adOpenKeySet
      oRs.LockType = adLockBatchOptimistic    
    Case "eh"  
  End Select
  WScript.Echo "oRs.CursorLocation: ", oRs.CursorLocation
  WScript.Echo "oRs.CursorType: ", oRs.CursorType
  WScript.Echo "oRs.LockType: ", oRs.LockType
  Select Case sAct
    Case "trout", "bob"
      oRs.Open "tLines", oConn, , adLockBatchOptimistic
      For nRec = 1 to nRecs
          oRs.AddNew
          oRs( "SampleText" ) = "This is line " & nRec
      Next
      oRs.UpdateBatch
      oRs.Close
    Case "eh" 
      oConn.BeginTrans
      Set oParm = CreateObject( "ADODB.Parameter" )
      With oParm
        .Name      = "A"
        .Type      = adVarChar
        .Value     = ""
        .Direction = adParamInput
        .Size      = 100
      End With
      Set oCmd = CreateObject( "ADODB.Command" )
      With oCmd
        Set .ActiveConnection = oConn
            .CommandText      = "INSERT INTO tLines (SampleText) VALUES (?)"
            .CommandType      = adCmdText
            .Parameters.Append oParm
      End With

      ReDim aData( 0 )
      For nRec = 1 to nRecs
          aData( 0 ) = "This is line " & nRec
          oCmd.Execute nRA, aData, adExecuteNoRecords + adCmdText
      Next
      oConn.CommitTrans 
  End Select

  WScript.Echo "#Recs:", oConn.Execute( "SELECT COUNT(SampleText) FROM tLines" ).Fields( 0 )
  WScript.Echo "First:", oConn.Execute( "SELECT TOP 1 * FROM tLines" ).Fields( 0 )

  oConn.Close

, вызываемый с / n: 200 и / a: trout, который показывает:

  #Recs: 0
  trout
  oRs.CursorLocation:  2
  oRs.CursorType:  0
  oRs.LockType:  1
  ... xpl.vbs(246, 11) Provider: Number of rows with pending changes exceeded the limit.

Думаю, я правильно воспроизвел вашу проблему.Для / a: bob:

  #Recs: 0
  bob
  oRs.CursorLocation:  3
  oRs.CursorType:  1
  oRs.LockType:  4
  #Recs: 200
  First: This is line 1
  xpl.vbs: Erfolgreich beendet. (0) [ 19.74219 secs ]

Таким образом, установка

  oRs.CursorLocation = adUseClient
  oRs.CursorType = adOpenKeySet
  oRs.LockType = adLockBatchOptimistic    

, как советуют Боб (и Microsoft), является одним из решений вашей проблемы.Чтобы набрать скорость, я ввел команду в транзакцию:

  oConn.BeginTrans
  Set oCmd = CreateObject( "ADODB.Command" )
  ...
  ReDim aData( 0 )
  For nRec = 1 to nRecs
      aData( 0 ) = "This is line " & nRec
      oCmd.Execute nRA, aData, adExecuteNoRecords + adCmdText
  Next
  oConn.CommitTrans 

Результат:

#Recs: 0
eh
oRs.CursorLocation:  2
oRs.CursorType:  0
oRs.LockType:  1
#Recs: 200
First: This is line 1
xpl.vbs: Erfolgreich beendet. (0) [ 1.47656 secs ]

От 20 до 2 секунд (без каких-либо суетливых свойств) мне кажется неплохим.

1 голос
/ 04 июля 2011

Если вы используете OLEDB, вам нужно установить для свойства CursorLocation значение adUseClient согласно следующей статье базы знаний: http://support.microsoft.com/kb/261297

Вы также можете рассмотреть возможность запуска меньшими партиями, если вы делаете медленно по 100 Кб одновременно

РЕДАКТИРОВАТЬ: да, adUseClient должен быть определен как = 3, или просто используйте номер 3. вместо него.

...