如何加快这个有效的代码,但速度很慢?

时间:2015-10-09 12:52:53

标签: vb.net excel vba excel-vba

我有这段代码,但在以后的程序中运行得太慢了:

    Sub Here()
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Dim srchLen, srchLen2, srchLen4, srchLen5, gName, nxtRw As Integer
    Dim g As Range

    'Clear Sheet 2 and Copy Column Headings
    Sheets(2).Cells.ClearContents
    'Determine length of Search Column from Sheet3
    srchLen = Sheets(3).Range("A" & Rows.Count).End(xlUp).Row
    'Loop through list in Sheet3, Column A. As each value is
    'found in Sheet1, Column A, copy it top the next row in Sheet2

    With Sheets(1).Columns("A")
        For gName = 1 To srchLen
            Set g = .Find(Sheets(3).Range("A" & gName), lookat:=xlWhole)
            If Not g Is Nothing Then
                nxtRw = Sheets(2).Range("A" & Rows.Count).End(xlUp).Row + 1
                g.EntireRow.Copy Destination:=Sheets(2).Range("A" & nxtRw)
            End If
        Next
    End With

' stage 2 Check my Local Stocks
    srchLen2 = Sheets(2).Range("A" & Rows.Count).End(xlUp).Row
    srchLen4 = Sheets(4).Range("A" & Rows.Count).End(xlUp).Row
    For i = 1 To srchLen4
        For j = 1 To srchLen2
            If Sheets(4).Rows(i).Columns(1).Value = Sheets(2).Rows(j).Columns(1).Value Then
                Sheets(2).Rows(j).Columns(2).Value = Sheets(2).Rows(j).Columns(2).Value + Sheets(4).Rows(i).Columns(2).Value
            End If
        Next j
    Next i

'EBAY CODE
    srchLen2 = Sheets(2).Range("A" & Rows.Count).End(xlUp).Row
    srchLen5 = Sheets(5).Range("K" & Rows.Count).End(xlUp).Row
    For j = 1 To srchLen2
        For i = 1 To srchLen5
            If Sheets(5).Rows(i).Columns(11).Value = "" Then i = i + 1
                If Sheets(2).Rows(j).Columns(1).Value = Sheets(5).Rows(i).Columns(11).Value Then
                    Sheets(5).Rows(i).Columns(8).Value = Sheets(2).Rows(j).Columns(2).Value
                End If
        Next i
    Next j

'website CODE
    srchLen2 = Sheets(2).Range("A" & Rows.Count).End(xlUp).Row
    srchLen6 = Sheets(6).Range("G" & Rows.Count).End(xlUp).Row
    For j = 1 To srchLen2
        For i = 1 To srchLen6
            If Sheets(6).Rows(i).Columns(7).Value = "" Then i = i + 1
                If Sheets(2).Rows(j).Columns(1).Value = Sheets(6).Rows(i).Columns(7).Value Then
                    Sheets(6).Rows(i).Columns(9).Value = Sheets(2).Rows(j).Columns(2).Value
                End If
        Next i
    Next j

    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Call Calculate
    End Sub

表1是我们经销商的库存清单,包含约65,000件物品(columnA = SKU)(ColumnB =数量)。

工作表2是一个结果页面,其中工作表3与工作表1进行比较,如果存在,则将其打印到工作表2中,然后在一种循环中将行线增加到下一行。

表1,2,3工作得很好,但计算过去' Stage 2 Check my local stocks时整个宏速度变慢。

eBay和网站代码似乎会因为FOR NEXT循环而减慢一切。

我在网络服务器上上传了一个小版the Excel file。请在运行之前对其进行病毒扫描。

将此代码复制粘贴到宏中,您应该很容易理解它的作用以及我想要实现的目标。它适用于我想要的东西,但它的速度很慢。

4 个答案:

答案 0 :(得分:0)

总体建议:

在过程开始时将Excel范围转换为数组。花费这么多时间的部分原因是Excel一次只能访问一个单元,这比访问内部范围数据要花费更长的时间。

例如,在程序开始时,创建一个名为' Website_Stock'的对象类,包含您关注的所有属性(索引号,名称,数量等),然后为每个网站的库存定义一个数组。然后就像你已经做的那样,计算你上面的第一行和最后一行,但是然后说出以下几点:

For i = 1 to lastrow
    Website_Stock(i).Index = Website_Stock_Range(x, y)
Next i

然后根据新创建的范围分配数组中的所有属性。类似的东西:

docker inspect $SWARM_AGENT_MASTER

*这只是伪代码

然后在创建它的最后,您可以像上面一样使用For循环,并且每次都不需要访问Excel工作表进行更改。

答案 1 :(得分:0)

使用ADO查询工作表而不是循环将节省大量时间,我做了这些更改并粘贴下面的代码来运行。我认为它能满足您的需求!

1添加标题(SKU,数量到"导入列表")

2添加标题(SKU,数量到"亚马逊结果")

3添加标题(SKU到"我们的产品")

在"网站上传中更改了标题"对它们进行编号而不是所有"字段数据1"

4添加名为" dump"

的工作表

5将此代码添加到模块并运行

Const SourceDirectory As String = "C:\MyDirectory"
Const Filename As String = "sample.xlsm"
Dim con As ADODB.Connection
Dim rs As ADODB.Recordset
Dim ws As Worksheet

Sub Here()
Set con = New ADODB.Connection
Set rs = New ADODB.Recordset
AddHeadersToAmazonResult
con.Open "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & SourceDirectory & Filename & "; Extended Properties=""Excel 8.0;HDR=Yes;"";"
rs.Open "Select il.* FROM ([imported list$] il INNER JOIN [Our products$] op on il.SKU=op.SKU)", con, adOpenStatic, adLockOptimistic, adCmdText
If Not rs.EOF Then
    Sheets("amazon result").Cells(2, 1).CopyFromRecordset rs
End If
rs.Close
Set rs = Nothing
Set rs = New ADODB.Recordset

''check stocks
rs.Open "SELECT ar.SKU, iif(isnull(ar.Quantity),0,ar.Quantity)+iif(isnull(hs.Quantity),0,hs.Quantity) " & _
        "FROM ( [amazon result$] ar LEFT JOIN  [holding stock$] hs on ar.SKU=hs.SKU)", _
        con, adOpenKeyset, adLockOptimistic
i = 2
While Not rs.EOF
    Sheets("amazon result").Cells(i, 1) = rs(0).Value
    Sheets("amazon result").Cells(i, 2) = rs(1).Value
    rs.MoveNext
    i = i + 1
Wend
rs.Close    

''ebay
rs.Open "SELECT * FROM [Amazon result$]", con, adOpenKeyset, adLockReadOnly
Set ws = Sheets("ebay upload")
LastRow = ws.Cells(65000, 11).End(xlUp).Row
For r = 2 To LastRow
If ws.Cells(r, 11).Value <> "" Then
    rs.Filter = "SKU='" & ws.Cells(r, 11).Value & "'"
    ws.Cells(r, 8).Value = rs(1)
End If
Next r
rs.Close
Set rs = Nothing 'killing here because it messes up the next query if you leave it open
Set rs = New ADODB.Recordset


''website

rs.Open "SELECT [field data 1], [field data 2], [field data 3], [field data 4], [field data 5], [field data 6], [field data 7], [field data 8], SKU, [field data 10], [field data 11], [field data 12] " & _
        "FROM ([website upload$] wu LEFT JOIN [amazon result$] ar " & _
        "ON wu.[field data 7]=ar.SKU)", _
        con, adOpenKeyset, adLockReadOnly
If Not rs.EOF Then
    Sheets("dump").Cells.Clear
    Sheets("dump").Cells(1, 1).CopyFromRecordset rs
    Sheets("website upload").Rows("2:65000").Clear
    Sheets("dump").UsedRange.Copy Sheets("website upload").Cells(2, 1)
End If
rs.Close


GoTo cleanup

errorhandler:
MsgBox "There was an error." & vbCrLf & vbCrLf & Err.Description, vbCritical

cleanup:
If rs.State = adStateOpen Then rs.Close
If con.State = adStateOpen Then con.Close
Set rs = Nothing
Set con = Nothing

End Sub

Sub AddHeadersToAmazonResult()
Sheets("amazon result").Cells.ClearContents
Sheets("amazon result").Cells(1, 1) = "SKU"
Sheets("amazon result").Cells(1, 2) = "Quantity"
End Sub

答案 2 :(得分:0)

以下是一些编码建议 - 可能无法帮助提高速度,在尝试使用完整数据集之前无法判断。

使用Option Explicit,以便了解您是否正确使用变量

`roboCode'sub生成一些代码,使工作表引用更通用。运行一次以生成代码并将其复制到正确的位置 - 模块调用wks和子init()。

使用工作表编号是一个非常糟糕的主意。 roboCode允许您通过名称进行寻址。

捕获错误。

不要在dim语句中使用一行 - 结果是对象/变体,而不是最后一个变量的类型。

对行计数/索引使用long。

尝试使用.Cells进行范围寻址。更容易编写代码,更清晰。

使用缩进 - 突出显示行并使用Tab和shift-Tab控制缩进

通过状态栏向外界通知进度,偶尔调用DoEvents以允许其他进程运行以及屏幕更新。你会看到这段代码随着它的进展而变慢(基于sample.xls) - 我认为Find是罪魁祸首。您可以考虑使用VB.Net解决方案而不是Excel VBA。访问可能会更好。

其他评论内联

Option Explicit

Sub roboCode()
    ' name worksheets
    Dim i As Integer
    Debug.Print "' global dim in module named 'wks'"
    For i = 1 To ThisWorkbook.Worksheets.Count
        Debug.Print "public wks" & Replace(ThisWorkbook.Worksheets(i).Name, " ", "_") & " as worksheet"
    Next i
    Debug.Print "' one time Set"
    For i = 1 To ThisWorkbook.Worksheets.Count
        Debug.Print "set wks" & Replace(ThisWorkbook.Worksheets(i).Name, " ", "_") & " = ThisWorkbook.Worksheets(""" & ThisWorkbook.Worksheets(i).Name & """)"
    Next i
End Sub
Sub Init()
    ' text from roboCode
    Set wks.Imported_list = ThisWorkbook.Worksheets("imported list")
    Set wks.Amazon_result = ThisWorkbook.Worksheets("amazon result")
    Set wks.Our_products = ThisWorkbook.Worksheets("Our products")
    Set wks.Holding_stock = ThisWorkbook.Worksheets("holding stock")
    Set wks.Ebay_upload = ThisWorkbook.Worksheets("ebay upload")
    Set wks.Website_upload = ThisWorkbook.Worksheets("website upload")
    Set wks.Personalised_Goods = ThisWorkbook.Worksheets("Personalised Goods")
    Set wks.Manual_checks = ThisWorkbook.Worksheets("Manual checks")
End Sub
Function RowCount(wks As Worksheet) As Long
    RowCount = wks.UsedRange.Rows.Count
End Function
Function ColCount(wks As Worksheet) As Long
    ColCount = wks.UsedRange.Columns.Count
End Function
Sub Here()
On Error GoTo Local_error

    Init
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
'    Dim srchLen, srchLen2, srchLen4, srchLen5, gName, nxtRw As Integer ' all Objects/Variants except nxtRw
    Dim srchLen As Long
    Dim srchLen2 As Long
    Dim srchLen4 As Long
    Dim srchLen5 As Long
    Dim srchLen6 As Long
    Dim gName As Long
    Dim rng As Range
    Dim i As Long
    Dim j As Long
    Dim nxtRw As Long

    'Clear Sheet 2 and Copy Column Headings
'    wks.Ebay_upload.Cells.ClearContents
    wks.Ebay_upload.UsedRange.Delete (xlUp)

    'Determine length of Search Column from Sheet3
'    srchLen = Sheets(3).Range("A" & Rows.Count).End(xlUp).Row
    srchLen = wks.Our_products.UsedRange.Rows.Count ' not used, RowCount() used instead

    'Loop through list in Sheet3, Column A. As each value is
    'found in Sheet1, Column A, copy it top the next row in Sheet2

    With wks.Imported_list.Columns(1)
        nxtRw = 1
        For gName = 1 To RowCount(wks.Our_products)
            ' I think this next statement is slowing things down, may be unavoidable
            Set rng = .Find(wks.Our_products.Cells(gName, 1))
            If Not rng Is Nothing Then
                nxtRw = nxtRw + 1
                ' copy may be slower than individual assigments
'                rng.EntireRow.Copy Destination:=wks.Amazon_result.Rows(nxtRw)
                wks.Amazon_result.Cells(nxtRw, 1) = rng.Value
                If nxtRw Mod 100 = 0 Then
                    Application.StatusBar = nxtRw
                    DoEvents
                End If
            End If
        Next
    End With

    ' ....
    Application.ScreenUpdating = True
    MsgBox "Done"
Local_exit:
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Application.StatusBar = False
    Exit Sub
Local_error:
    Application.ScreenUpdating = True
    MsgBox Err & " " & Err.Description ' hit ctrl-break if you get here, then set next to Resume for debug
    Resume Local_exit
    Resume
End Sub

答案 3 :(得分:0)

基于提供的文件

  • 发布代码:约32分钟
  • 此解决方案:约2分钟
Option Explicit

Public Sub HereArrays()
    Dim lr1 As Long, lr2 As Long, lr3 As Long
    Dim v1 As Variant, v2 As Variant, v3 As Variant
    Dim i1 As Long, i2 As Long, i3 As Long, t As Double, t1 As Double

    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual

    t = Timer: t1 = t
    'Clear Sheet 2
    Sheets(2).UsedRange.EntireColumn.Delete

    lr1 = Sheets(1).Range("A" & Rows.Count).End(xlUp).Row
    lr2 = lr1
    lr3 = Sheets(3).Range("A" & Rows.Count).End(xlUp).Row
    v1 = Sheets(1).Range("A1:B" & lr1)
    v2 = Sheets(2).Range("A1:B" & lr1)
    v3 = Sheets(3).Range("A1:B" & lr3)
    i2 = 1
    For i3 = 1 To lr3
        For i1 = 1 To lr1
            If v3(i3, 1) = v1(i1, 1) Then
                v2(i2, 1) = v1(i1, 1)
                v2(i2, 2) = v1(i1, 2)
                i2 = i2 + 1
                Exit For            'exit inner For only
            End If
        Next
    Next
    Sheets(2).Range("A1:B" & lr2) = v2
    Debug.Print "HereArrays - 1 of 4 - Duration: " & Timer - t & " seconds"
    t = Timer

    ' stage 2 Check my Local Stocks
    lr1 = Sheets(4).Range("A" & Rows.Count).End(xlUp).Row
    lr2 = Sheets(2).Range("A" & Rows.Count).End(xlUp).Row
    v1 = Sheets(4).Range("A1:B" & lr1)
    v2 = Sheets(2).Range("A1:B" & lr2)
    For i1 = 1 To lr1
        For i2 = 1 To lr2
            If v1(i1, 1) = v2(i2, 1) Then
                v2(i2, 2) = v2(i2, 2) + v1(i1, 2)
                Exit For            'exit inner For only
            End If
        Next
    Next
    Sheets(2).Range("A1:B" & lr2) = v2
    Debug.Print "HereArrays - 2 of 4 - Duration: " & Timer - t & " seconds"
    t = Timer

    'EBAY CODE
    lr1 = Sheets(5).Range("K" & Rows.Count).End(xlUp).Row
    v1 = Sheets(5).Range("K1:K" & lr1)
    v3 = Sheets(5).Range("H1:H" & lr1)
    v2 = Sheets(2).Range("A1:B" & lr2)
    For i2 = 1 To lr2
        For i1 = 1 To lr1
            If Len(v1(i1, 1)) = 0 Then i1 = i1 + 1
            If v2(i2, 1) = v1(i1, 1) Then
                v3(i1, 1) = v2(i2, 2)
                Exit For            'exit inner For only
            End If
        Next
    Next
    Sheets(5).Range("H1:H" & lr1) = v3
    Debug.Print "HereArrays - 3 of 4 - Duration: " & Timer - t & " seconds"
    t = Timer

    'website CODE
    lr1 = Sheets(6).Range("G" & Rows.Count).End(xlUp).Row
    v1 = Sheets(6).Range("G1:G" & lr1)
    v3 = Sheets(6).Range("I1:I" & lr1)
    v2 = Sheets(2).Range("A1:B" & lr2)
    For i2 = 1 To lr2
        For i1 = 1 To lr1
            If Len(v1(i1, 1)) = 0 Then i1 = i1 + 1
            If v2(i2, 1) = v1(i1, 1) Then
                v3(i1, 1) = v2(i2, 2)
                Exit For            'exit inner For only
            End If
        Next
    Next
    Sheets(6).Range("I1:I" & lr1) = v3
    Debug.Print "HereArrays - 4 of 4 - Duration: " & Timer - t & " seconds"

    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Call Calculate

    Debug.Print "HereArrays - Total  - Duration: " & Timer - t1 & " seconds"
    'HereArrays - 1 of 4 - Duration: 86.2109375 seconds
    'HereArrays - 2 of 4 - Duration: 0.328125 seconds
    'HereArrays - 3 of 4 - Duration: 0.25 seconds
    'HereArrays - 4 of 4 - Duration: 16.47265625 seconds
    'HereArrays - Total  - Duration: 103.26171875 seconds
End Sub

基本上,这是初始代码“翻译”使用数组而不是与Ranges交互

详细测量

发布代码:

'Here - 1 of 4 - Duration: 654.28515625 seconds

'Here - 2 of 4 - Duration: 24.5078125 seconds
'Here - 3 of 4 - Duration: 13.43359375 seconds
'Here - 4 of 4 - Duration: 1195.375 seconds

'Here - Total  - Duration: 1887.6015625 seconds

此代码:

'HereArrays - 1 of 4 - Duration: 86.2109375 seconds

'HereArrays - 2 of 4 - Duration: 0.328125 seconds
'HereArrays - 3 of 4 - Duration: 0.25 seconds
'HereArrays - 4 of 4 - Duration: 16.47265625 seconds

'HereArrays - Total  - Duration: 103.26171875 seconds