使用 ADODB 记录集 UpdateBatch 方法更新 SQL Server

问题描述 投票:0回答:1

我正在尝试在 Excel VBA 中使用 ADO 在 SQL Server 中填充单列临时表。我的代码非常慢,即 1,000 行需要 145 秒。

有没有更快的方法涉及不涉及操作原始 SQL 字符串的可维护的优雅代码?我喜欢 .AddNew 和 .UpdateBatch ... 如果做不到这一点,最快的方法是什么?

Private Sub StackOverflowPopTempTable(cn As ADODB.Connection)

Dim rs As ADODB.Recordset
Dim row As Long
Dim strSql As String
Dim row_count As Long
Dim t As Single
t = Timer

Set rs = New ADODB.Recordset
    
'Create a temporary table
strSql = "IF OBJECT_ID('tempdb..##tbl_dummy_data', 'U') IS NOT NULL " & _
            "DROP TABLE ##tbl_dummy_data; " & _
            "CREATE TABLE ##tbl_dummy_data ( " & _
            "dummy_data VARCHAR(20) PRIMARY KEY " & _
            ");"
cn.Execute strSql

'Add masterkeys to this exclusion table
strSql = "SELECT * FROM ##tbl_dummy_data"
rs.Open strSql, cn, adOpenStatic, adLockBatchOptimistic


row_count = 1000
For row = 1 To row_count
    rs.AddNew
    rs("dummy_data") = "a" & row
Next row
Debug.Print Timer - t
rs.UpdateBatch
Set rs = Nothing

Debug.Print Timer - t
    
End Sub

UpdateBatch语句最多只需要半秒。剩下的 2 分钟左右是 UpdateBatch 语句。

非常感谢-我会同时更新我发现的任何东西......

更新一

这需要相同的时间

cn.BeginTrans
row_count = 1000
For row = 1 To row_count
    strSql = "INSERT INTO ##tbl_dummy_data VALUES ('a" & row & "')"
    cn.Execute strSql
Next row
Debug.Print Timer - t
cn.CommitTrans
Debug.Print Timer - t`

更新 2

IF OBJECT_ID('tempdb..##tbl_dummy_data', 'U') IS NOT NULL
    DROP TABLE ##tbl_dummy_data;
CREATE TABLE ##tbl_dummy_data (
    dummy_data VARCHAR(20) PRIMARY KEY
);

Insert Into ##tbl_dummy_data
    Select Cast(rand(checksum(newid()))*1000000  as int);
go 1000

服务器端需要 2 分钟

更新三

这只需要几分之一秒,所以我怀疑 VBA 正在做单独的交易?即使我使用 .BeginTrans 和 .CommitTrans?

DECLARE @counter INT 
        
SET @counter = 0 
BEGIN TRANSACTION
WHILE @counter < 1000
BEGIN 
   Insert Into ##tbl_dummy_data
    Select Cast(rand(checksum(newid()))*1000000  as int);
   SET @counter = @counter + 1
END
COMMIT TRANSACTION

更新四

检查供应商是否支持交易。显然是这样!

?cn.Properties("Transaction DDL").Value
 8 
sql-server excel vba ado
1个回答
0
投票

一个答案(尽管它是 v hacky)似乎是将所有 INSERT 放入一个字符串中。这需要 1 秒

Private Sub StackOverflowPopTempTableRaw(cn As ADODB.Connection)
    Dim row As Long
    Dim strSql As String
    Dim row_count As Long
    Dim t As Single
    t = Timer

    'Create a temporary table
    strSql = "IF OBJECT_ID('tempdb..##tbl_dummy_data', 'U') IS NOT NULL " & _
                "DROP TABLE ##tbl_dummy_data; " & _
                "CREATE TABLE ##tbl_dummy_data ( " & _
                "dummy_data VARCHAR(20) PRIMARY KEY " & _
                ");"
    cn.Execute strSql
    
    'Add masterkeys to this exclusion table
    row_count = 1000
    For row = 1 To row_count
        strSql = strSql & "INSERT INTO ##tbl_dummy_data VALUES ('a" & row & "'); "
    Next row
    cn.Execute strSql
    Debug.Print Timer - t
End Sub
© www.soinside.com 2019 - 2024. All rights reserved.