Vb.net 如何加快这段代码的运行速度,但速度非常慢?

Vb.net 如何加快这段代码的运行速度,但速度非常慢?,vb.net,vba,excel,Vb.net,Vba,Excel,我有这段代码,但在后面的过程中运行得太慢: 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 Colum

我有这段代码,但在后面的过程中运行得太慢:

    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是我们经销商的库存清单,其中包含约65k项columnA=SKU ColumnB=数量

第2页是一个结果页,其中第3页与第1页进行比较,如果存在,则将其打印到第2页,然后行行将以某种循环方式递增到下一行

表1、2、3运行得很好,但在计算过去的“第2阶段检查我的本地股票”时,整个宏观经济放缓

易趣和网站代码似乎减慢了一切,可能是因为下一个循环的原因

我已经在我们的Web服务器上上传了一个小版本的。请在运行之前对其进行病毒扫描


将此代码复制粘贴到宏中,您应该很容易理解它的作用以及我试图实现的目标。它可以满足我的需求,但速度太慢。

总体建议:

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

例如,在您的过程开始时,创建一个名为“Website_Stock”的对象类,包含您关心的索引、名称、数量等所有属性,然后为每个网站的股票定义一个数组。然后,正如你已经做的那样,计算第一行和最后一行,正如你上面所做的那样,但然后说一些大致如下的话:

Redim Website_Stock(1 to lastrow)
Set  Website_Stock_Range to Range(Firstcolumn & firstrow, Lastcolumn & lastrow)
然后根据新创建的范围指定数组中的所有属性。比如:

For i = 1 to lastrow
    Website_Stock(i).Index = Website_Stock_Range(x, y)
Next i
*这只是伪代码


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

使用ADO查询工作表而不是循环将节省大量时间,我进行了这些更改并粘贴了下面的代码以运行。我想它正是你想要的

1将标题SKU、数量添加到导入列表

2将标题SKU、数量添加到亚马逊结果

3将标题SKU添加到我们的产品中

4更改网站上载中的标题,以对其进行编号,而不是对所有字段数据进行编号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

以下是一些编码建议-可能对速度没有帮助,除非您尝试使用完整的数据集,否则无法判断

使用Option Explicit,以便知道是否正确使用了变量

`“机器人代码”子系统生成一些代码,使图纸参考更通用。运行它一次以生成代码并将其复制到适当的位置—模块调用wks和子初始化

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

捕捉你的错误

请勿将一行用于dim语句-结果对象/变量,而不是最后一个变量的类型

对行计数/索引使用long

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

使用缩进-高亮显示行,并使用Tab和shift选项卡控制缩进

通过状态栏向外部通知进度,偶尔调用DoEvents以允许其他进程运行并更新屏幕。您将看到这段代码在基于sample.xls的过程中变得越来越慢,我认为这是罪魁祸首。您可以考虑用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

根据提供的文件

张贴代码:约32分钟 此解决方案:大约2分钟 基本上,这是转换为使用数组而不是与范围交互的初始代码

详细测量

张贴代码:

'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

这听起来像是一个愚蠢的问题,但是是否有任何格式化的单元,即字体,如表等等?考虑把这个问题移到CoDeEvIEW.StAccExchange。com -它们只处理当前正在运行的代码的改进;但这并不意味着你不能在这里寻求帮助。而且你的行数应该是长的而不是变量尝试了这段代码,首先运行了roboCode,但在运行init时,我得到了一个变量未定义的错误。当我有更多的时间时,我会再看一遍,但谢谢你的投入。
'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