VB6 Ms Access数据库编辑大量记录

时间:2013-06-17 07:16:07

标签: ms-access vb6

我需要使用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

这真的很简单。真实的是,我忘了提到,计算机的硬盘驱动器不断发出红色/写入。这实际上是问题所在。如此沉重的负载,就无法影响性能。

我首先想到的是查询生成的记录集,请记住我们有1-2万条记录,导致这个问题。我想它存在于硬盘驱动器和RAM中的一些临时位置。因此,执行.Edit和.Update可能是一个问题,首先将光标定位在正确的位置,然后再写。

不确定。可能会有一位专家向我展示出一条出路。

顺便说一下。我也尝试过更换                     Loop Until Data1(1).Recordset.EOF = True 具有固定长度周期的语句,因为我也读过,这次检查Recordset.EOF也会降低性能。

提前谢谢!

4 个答案:

答案 0 :(得分:2)

我创建了一个名为test的表格,其中包含字段nf(n)

定时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

这比任何记录集方法都快。例如。大约200万条记录,没有交易需要大约20秒,交易大约需要18-19秒,更新查询大约需要14秒。

这一切都假设要更新的字段取决于从该记录中的其他恶魔计算的值

要真正加快这些行动,有时候这取决于具体情况,如果不适用,则需要更多细节。

编辑:使用旧核心2双人机+字段上没有索引

答案 1 :(得分:1)

我唯一的建议是在您的情况下可能不起作用,是使用更新查询进行批量更新。

这可能有效的三种情况:

如果可以从其他字段计算 Sort_Value ,那就是一个简单的UPDATE查询,但我相信您已经看过了。

如果 Sort_Value 可以从其他记录(如之前的记录)中计算出来,那么你可以写一个更复杂的UPDATE查询(我在这里看到了一些非常复杂的查询)。

最后,如果将相同的Sort_Value 应用于大量记录,则可以根据这些记录发出UPDATE查询。因此,如果 Sort_Value 可能是10个不同的值,那么所有更新都将在10个UPDATE查询中完成。


如果您告诉我们您在哪里获得 Sort_Value ,我们可能会为您提供进一步的帮助。


根据我的测试,这里有一些不要工作来加速编辑/更新命令。这是使用10,000个记录的表格完成的,有1,000,000个更新。

  • RS(1)而不是RS(“名称”)。这是在另一个网站上提出的 实际上增加了20%的时间。 (25秒/ 21秒)
  • BeginTrans / CommitTrans对未编入索引的字段没有任何影响,并且 在索引字段上快1%。 (未索引:11秒[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

答案 2 :(得分:1)

虽然在某些情况下可能需要,但应避免迭代记录集以更新字段。

更明智的做法是编写SQL更新查询。

如果您的表太大,您必须小心选择索引,特别是主键。

然后,您可以根据您的PK划分数据,并更新第一组中的所有记录,然后更新第二组,第三组......

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

您对表格中的所有分部重复此操作(按代码)。

现在,问题是 - 你能想到一个创建所需Sort_value的Access函数吗?

请注意,如果Field_A是您的主键,则不应更改它。否则,每次更新一些记录时,所有表格都会重新排列,这对您的HD /处理器来说将是很多工作。在这种情况下,您应该使用不同的PK,并在Field_A上创建索引,而不是PK。

答案 3 :(得分:0)

为了提高性能,您可以使用ADODB对象的UpdateBatch方法。但要使用此功能,它需要:

  1. adOpenStatic cursorType
  2. adLockBatchOptimistic LockType
  3. 记录集对象上的

    此外,您还可以使用adUseClient CursorLocation在操作期间在客户端而不是服务器上加载。

    更进一步,不要使用rec.EOF测试。您应该从1 to rec.RecordCount

    开始使用for循环
      

    Worth mentioning:在ADODB遍历所有记录之前阅读rec.RecordCount是不可靠的。因此,请MoveLastMoveFirst确保记录正确。

    使用以下代码作为提示:

    set con = Server.CreateObject("ADODB.Connection")
    con.Provider = "Microsoft.Jet.OLEDB.4.0"
    con.Open(Server.Mappath("MyShopDB.mdb"))
    set rec = Server.CreateObject("ADODB.recordset")
    sql = "SELECT * FROM Employees"
    
    rec.CursorLocation = adUseClient
    rec.CursorType = adOpenStatic
    rec.LockType = adLockBatchOptimistic
    
    rec.Open sql, con
    
    if not rec.EOF then            ' rescue no records situation
        rec.moveLast               ' let it see all records
        rec.moveFirst
    end if
    
    cnt = rec.RecordCount          ' avoid reading each time in loop test
    
    if cnt > 0 then
        for i = 1 to cnt
            rec.Fields("FIELD").value = Sort_Value
            '...
            '...
            '...
            rec.MoveNext
        next i
        rec.UpdateBatch
    end if
    
    rec.Close
    con.Close
    

    当我从VB切换到PHP时,已经超过3年了。可能会遗漏一些曲目。 Please note:我还没有执行此代码。它可能包含一些小问题,但这应该足以用于指示目的。

    您还可以尝试将批次拆分为片段以查看对效果的影响。