通过 VBA 拆分 Access 数据库需要很长时间

Splitting Access database via VBA takes suddenly ages

我有一个 MS Access 数据库。数据库版本是 2002-2003(因此是 mdb)。从该数据库中,我将几个字段导出到临时 table 中,以便在网站上表示它们。由于有一个字段有多个逗号分隔的条目,我将它们拆分,以便每个记录每个字段只有一个条目。

假设一本德英词典有以下记录:

 en | de
 building | Gebäude,Bauwerk

我想拆分如下:

 en | de
 building | Gebäude
 building | Bauwerk

我使用的 VBA 函数过去工作正常。该数据库有大约 100.000 条记录。拆分过去大约需要 30 分钟。现在需要一整天。

这是函数:

    Public Sub commasplitfield4()
    Dim rstObj As DAO.Recordset, dbObj As DAO.Database
    Dim InsertSQL As String
    Set dbObj = CurrentDb()
    Set rstObj = dbObj.OpenRecordset("qry-export")
    DoCmd.SetWarnings False
    Do While Not rstObj.EOF
        Dim memArr() As String
        memArr = Split(rstObj.Fields("field4"), ",")
        For i = 0 To UBound(memArr)
            InsertSQL = "INSERT INTO exporttemp(field1,field2,field3,field4) VALUES (""" & rstObj.Fields("field1") _
            & """, """ & rstObj.Fields("field2") _
            & """, """ & rstObj.Fields("field3") & """, """ & memArr(i) & """)"
            DoCmd.RunSQL (InsertSQL)
        Next
        rstObj.MoveNext
    Loop
DoCmd.SetWarnings True
End Sub

我不能说它到底是从什么时候开始需要这么长时间的,但我可以说从 Windows 7 更改为 Windows 10 并没有什么不同。我在 Windows 10 上使用了很长时间,但它以前仍然运行良好。此外,从 Access 2007 迁移到 2010,然后迁移到 2019 并没有什么不同,至少一次没有。

为了检查错误可能出在哪里,我检查了以下清单:

None 没有table 差异。

有什么想法吗?

我无法解释你的问题的确切原因,但我认为循环遍历记录集和循环数组需要很多时间。

在 Excel 中使用 vba 用逗号分隔字符似乎更快。 示例源数据是 1000000 条记录, 每个逗号分隔的内容每条记录写两条,转换后的数据记录以2000000条数据测试

  1. 将Access的原始数据导入Excel(Sheets(1))。 (例表2)~~> 0.7617188秒
  2. 转换数据,将导入的Sheets(1)数据用逗号隔开。 --> 页数(2) ~~> 21.58594 秒
  3. 通过 Access 应用程序从 Sheets(2) 加载数据。 ~~> 5 分钟

  1. 导入Access原始数据

 Sub exeSQLgetdata()
 
    Dim Rs As ADODB.Recordset
    Dim strConn As String
    Dim i As Integer
    Dim Fn As String
    Dim Ws As Worksheet
    
    Dim st, et
    
    st = Timer
    
    Set Ws = Sheets(1)
    
    Fn = ThisWorkbook.Path & "\" & "Database9.accdb" '<~~ your database path & name
    
    strConn = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
        "Data Source=" & Fn & ";"
 
    Set Rs = CreateObject("ADODB.Recordset")
    strSQL = "Select field1,field2, field3, field4  from [table2]" '<~~ your raw data table
    
    Rs.Open strSQL, strConn
    
    If Not Rs.EOF Then
        With Ws
            For i = 0 To Rs.Fields.Count - 1
                .Cells(1, i + 1) = Rs.Fields(i).Name
            Next i
            .UsedRange.Offset(1).Clear
            .Range("a2").CopyFromRecordset Rs
        End With
    End If
    Rs.Close
    Set Rs = Nothing
    et = Timer
    
    Debug.Print "Get Data time : " & et - st & " seconds" '<~~ get data from access database
End Sub

  1. 转换数据,将导入的Sheets(1)的数据用逗号分隔。

Sub splitData()
    Dim vR(1 To 1000000, 1 To 4)
    Dim vDB As Variant
    Dim i As Long, n As Long
    Dim k As Variant, v As Variant
    Dim Ws As Worksheet
    Dim toWs As Worksheet
    Dim st, et
    
    st = Timer
    
    Set Ws = Sheets(1)
    Set toWs = Sheets(2)
    
    vDB = Ws.Range("a1").CurrentRegion
    
    For i = 1 To UBound(vDB, 1)
        k = Split(vDB(i, 4), ",")
        For Each v In k
            n = n + 1
            vR(n, 1) = vDB(i, 1)
            vR(n, 2) = vDB(i, 2)
            vR(n, 3) = vDB(i, 3)
            vR(n, 4) = v
        Next v
        DoEvents
    Next i

    With toWs
        .UsedRange.Clear
        .Range("a1").Resize(UBound(vR, 1), UBound(vR, 2)) = vR
    End With
    et = Timer
    Debug.Print "Split time : " & et - st & " seconds"
End Sub

迄今为止最好的答案是来自 HansUp 的答案。现在只需几分钟,而不是一整天。我什至不能恰当地感谢 HansUp,因为他把解决方案放在了旁注中。

令人惊讶的是,实际上我几乎不需要更改代码。所以,解决方案是修改代码如下:

Public Sub commasplitfield4()
    Dim rstObj As DAO.Recordset, dbObj As DAO.Database
    Dim InsertSQL As String
    Set dbObj = CurrentDb()
    Set rstObj = dbObj.OpenRecordset("qry-export")
    DoCmd.SetWarnings False
    Do While Not rstObj.EOF
        Dim memArr() As String
        memArr = Split(rstObj.Fields("field4"), ",")
        For i = 0 To UBound(memArr)
            InsertSQL = "INSERT INTO exporttemp(field1,field2,field3,field4) VALUES (""" & rstObj.Fields("field1") _
            & """, """ & rstObj.Fields("field2") _
            & """, """ & rstObj.Fields("field3") & """, """ & memArr(i) & """)"
            'DoCmd.RunSQL (InsertSQL)
            dbObj.Execute (InsertSQL), dbFailOnError 'this line made the difference
        Next
        rstObj.MoveNext
    Loop
'DoCmd.SetWarnings True
End Sub