如何在 Microsoft Access 中加快批量 'upsert'
How to speed up bulk 'upsert' in Microsoft Access
我正在使用 VBA 字典在 Access 中执行 'upsert'。我正在循环我的字典键,如果该键存在于 Access table 中,那么我会更新它。如果没有,它会插入它。然而,我的 table 包含 200k+ 行,这使得代码执行得非常慢(例如,5 分钟,甚至 5% 都没有完成),因为迭代需要在整个 table 中搜索 [=26] =](我的钥匙)。
有什么方法可以显着加快这个过程吗?
我的代码如下,如有任何帮助,我们将不胜感激。
Sub UpdateDatabase(dict As Object)
Dim db As Database
Dim rs As DAO.Recordset
Set db = OpenDatabase("C:\XXX\myDB.accdb")
Set rs = db.OpenRecordset("MyTable", dbOpenDynaset)
For Each varKey In dict.Keys()
'Table is searched for key
rs.FindFirst "[LOCID] = '" & varKey & "'"
If rs.NoMatch Then
'If the key was not found, insert it
rs.AddNew
rs!LOCID = varKey
rs![Status] = "To Start"
rs.Update
Else
'If the key was found, update its status
rs.Edit
rs![Status] = "Done"
rs.Update
End If
Next
rs.Close
db.Close
Application.StatusBar = False
End Sub
编辑:
我发现了上面代码的瓶颈。这是行:
rs.FindFirst "[LOCID] = '" & varKey & "'"
这用于查找密钥是否在数据库中。删除它(并简单地插入新数据)可以加快这个过程,并且可以在几秒钟内完成。有没有一种快速的方法来确定一个值是否已经在 table?
中
首先:
字典集合有多大。 (5、10 或 1000???)。
接下来,LOCID 是 table“MyTable”中的索引列。
如果LOCID已经是一个索引列,那么可以使用下面的代码。它应该将速度提高大约 100 倍或更多倍:
假定 table 不是链接的 table,但实际上是数据库中的 table。
请注意,您必须将有问题的 table 打开为“actable”——这是默认设置,所以我删除了 dbOpenDynaset)
这段代码可以解决问题:
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = OpenDatabase("C:\XXX\myDB.accdb")
Set rs = db.OpenRecordset("MyTable") ' <--- note this!!!
rs.Index = "LOCID"
For Each varKey In dict.Keys()
'Table is searched for key
rs.Seek "=", varKey
If rs.NoMatch = True Then
'If the key was not found, insert it
rs.AddNew
rs!LOCID = varKey
rs![Status] = "To Start"
rs.Update
Else
'If the key was found, update its status
rs.Edit
rs![Status] = "Done"
rs.Update
End If
Next
rs.Close
db.Close
您还需要确定列 LOCID 上的实际索引的名称。我在上面使用了 LOCID,但你最好用 access 打开数据库,将 table 切换到设计模式,然后点击功能区 "indexs" 按钮。如果 LOCID 是主键,那么索引很可能被命名为 PrimaryKey。所以你需要索引的名称。
同上其他人的建议;从根本上不要做一个循环。执行操作查询(追加或更新)。
这是'programmer'和'database developer'之间最常见的区别……
我正在使用 VBA 字典在 Access 中执行 'upsert'。我正在循环我的字典键,如果该键存在于 Access table 中,那么我会更新它。如果没有,它会插入它。然而,我的 table 包含 200k+ 行,这使得代码执行得非常慢(例如,5 分钟,甚至 5% 都没有完成),因为迭代需要在整个 table 中搜索 [=26] =](我的钥匙)。
有什么方法可以显着加快这个过程吗? 我的代码如下,如有任何帮助,我们将不胜感激。
Sub UpdateDatabase(dict As Object)
Dim db As Database
Dim rs As DAO.Recordset
Set db = OpenDatabase("C:\XXX\myDB.accdb")
Set rs = db.OpenRecordset("MyTable", dbOpenDynaset)
For Each varKey In dict.Keys()
'Table is searched for key
rs.FindFirst "[LOCID] = '" & varKey & "'"
If rs.NoMatch Then
'If the key was not found, insert it
rs.AddNew
rs!LOCID = varKey
rs![Status] = "To Start"
rs.Update
Else
'If the key was found, update its status
rs.Edit
rs![Status] = "Done"
rs.Update
End If
Next
rs.Close
db.Close
Application.StatusBar = False
End Sub
编辑:
我发现了上面代码的瓶颈。这是行:
rs.FindFirst "[LOCID] = '" & varKey & "'"
这用于查找密钥是否在数据库中。删除它(并简单地插入新数据)可以加快这个过程,并且可以在几秒钟内完成。有没有一种快速的方法来确定一个值是否已经在 table?
中首先: 字典集合有多大。 (5、10 或 1000???)。
接下来,LOCID 是 table“MyTable”中的索引列。
如果LOCID已经是一个索引列,那么可以使用下面的代码。它应该将速度提高大约 100 倍或更多倍:
假定 table 不是链接的 table,但实际上是数据库中的 table。
请注意,您必须将有问题的 table 打开为“actable”——这是默认设置,所以我删除了 dbOpenDynaset)
这段代码可以解决问题:
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = OpenDatabase("C:\XXX\myDB.accdb")
Set rs = db.OpenRecordset("MyTable") ' <--- note this!!!
rs.Index = "LOCID"
For Each varKey In dict.Keys()
'Table is searched for key
rs.Seek "=", varKey
If rs.NoMatch = True Then
'If the key was not found, insert it
rs.AddNew
rs!LOCID = varKey
rs![Status] = "To Start"
rs.Update
Else
'If the key was found, update its status
rs.Edit
rs![Status] = "Done"
rs.Update
End If
Next
rs.Close
db.Close
您还需要确定列 LOCID 上的实际索引的名称。我在上面使用了 LOCID,但你最好用 access 打开数据库,将 table 切换到设计模式,然后点击功能区 "indexs" 按钮。如果 LOCID 是主键,那么索引很可能被命名为 PrimaryKey。所以你需要索引的名称。
同上其他人的建议;从根本上不要做一个循环。执行操作查询(追加或更新)。
这是'programmer'和'database developer'之间最常见的区别……