大型记录集 (VBA) 的 MS Access 插入慢

Posted

技术标签:

【中文标题】大型记录集 (VBA) 的 MS Access 插入慢【英文标题】:MS Access Insert Into Slow for Large Recordset (VBA) 【发布时间】:2016-04-25 11:47:40 【问题描述】:

我有一段代码创建一个新表,然后尝试将记录集值复制到表中。唯一的问题是它非常慢,并且在执行下面的插入部分时访问会显示加载符号。目前这个问题正在发生插入 500 条记录,但是当我获得最终数据集时,我需要插入大约 10,000 到 20,000 条记录。

I = 1
DoCmd.SetWarnings False
RecordSet1.MoveFirst
Do While Not RecordSet1.EOF = True
    SQL = "INSERT INTO " & FullName & " ("
    For Each field In RecordSet1.fields()
        SQL = SQL & " " & Replace(field.Name, ".", "_") & ","
    Next field
    SQL = SQL & "ValidationCheck)"
    SQL = SQL & " VALUES("
    For Each field2 In RecordSet1.fields()
        SQL = SQL & "'" & field2.Value & "',"
    Next field2
    SQL = SQL & Matches(I) & ")"
    DoCmd.RunSQL (SQL)
    RecordSet1.MoveNext
    I = I + 1
Loop

我想知道的是,有什么办法可以加快速度吗?还是有更好的方法? (我想要做的是在运行时创建一个表,其中包含来自 RecordSet 的一组唯一字段,并添加一个额外的列,其中包含存储在 Match 数组中的每个 Record 的布尔值)。创建工作正常,但是上面的插入代码很慢。

【问题讨论】:

如果使用 VBA 的性能太慢,我会尝试创建一个已保存的查询。如果您可以用纯 SQL 编写此代码,Access 将保存查询计划,您应该会看到更好的性能。 嗨,马克,感谢您的建议。我实际上已经尝试过了,它在一定程度上提高了性能。当然,我正在失去表结构的灵活性。您有任何进一步的性能提升想法吗? 我会尽你所能来准备数据和/或表格,并尽量减少循环/字符串操作。我也不确定Matches(I) 是什么。您能否设置一个计时器并查看性能影响实际发生的位置? ADO 不是更快吗? 【参考方案1】:

是的,使用 DAO。这么快。此示例复制到同一个表,但您可以轻松修改它,以便在两个表之间复制:

Public Sub CopyRecords()

  Dim rstSource   As DAO.Recordset
  Dim rstInsert   As DAO.Recordset
  Dim fld         As DAO.Field
  Dim strSQL      As String
  Dim lngLoop     As Long
  Dim lngCount    As Long

  strSQL = "SELECT * FROM tblStatus WHERE Location = '" & _
                "DEFx" & "' Order by Total"

  Set rstInsert = CurrentDb.OpenRecordset(strSQL)
  Set rstSource = rstInsert.Clone
  With rstSource
    lngCount = .RecordCount
    For lngLoop = 1 To lngCount
      With rstInsert
        .AddNew
          For Each fld In rstSource.Fields
            With fld
              If .Attributes And dbAutoIncrField Then
                ' Skip Autonumber or GUID field.
              ElseIf .Name = "Total" Then
                ' Insert default value.
                rstInsert.Fields(.Name).Value = 0
              ElseIf .Name = "PROCESSED_IND" Then
                rstInsert.Fields(.Name).Value = vbNullString
              Else
                ' Copy field content.
                rstInsert.Fields(.Name).Value = .Value
              End If
            End With
          Next
        .Update
      End With
      .MoveNext
    Next
    rstInsert.Close
    .Close
  End With

  Set rstInsert = Nothing
  Set rstSource = Nothing

End Sub

【讨论】:

【参考方案2】:

对于循环中的多个插入,不要使用 SQL INSERT 语句。而是使用 DAO.Recordset.AddNew

看到这个答案:https://***.com/a/33025620/3820271

作为积极的副作用,您的代码将变得更易读,并且您不必处理不同数据类型的多种格式。

For Each field In RecordSet1.Fields
     rsTarget(field.Name) = field.Value
Next field

【讨论】:

谢谢安德烈,我对解决方案有点不清楚。因此,您建议将记录集中的所有内容复制到一个新记录集中(rsTarget),这样我就可以在 Match 数组中为每条记录添加我的 vba 生成值?如何将 rsTarget 记录集写入新表?

以上是关于大型记录集 (VBA) 的 MS Access 插入慢的主要内容,如果未能解决你的问题,请参考以下文章

使用 VBA 将 MS Access 记录集导出到 Excel 中的多个工作表/选项卡会生成只读文件

使用 vba 在 MS-Access 前端中来自 MySQL 存储过程的多个结果集?

为啥要克隆 MS-Access 记录集?

在大型 VBA/MS Access 项目中查找语法错误

不断增长的 MS Access 文件大小问题

提高计算 MS-Access 中大型数据集 7 天滚动平均值的查询的性能