Processamento Eficiente de Dados
Deslize para mostrar o menu
Até agora, tudo foi feito célula por célula — adequado para cinco pedidos, mas extremamente lento para cinquenta mil. A solução é parar de manipular a planilha célula por célula e, em vez disso, mover todo o bloco para um array na memória, processá-lo lá e gravá-lo de volta de uma só vez.
Lendo um Intervalo para um Array
Dim dataArr As Variant
dataArr = ws.Range("A2:I6").Value ' one read, not 45 individual reads
dataArr agora é um array 2D na memória: dataArr(1,1) é ORD1001, dataArr(1,4) é "Laptop Stand", e assim por diante — arrays VBA lidos de um intervalo são baseados em 1, não em 0, o que é uma armadilha comum.
Processando o Array
Ocorre com loops comuns — mas agora você está percorrendo a memória, o que é milhares de vezes mais rápido do que percorrer a planilha:
Dim i As Long
Dim recalculated As Double
For i = 1 To UBound(dataArr, 1)
recalculated = dataArr(i, 5) * dataArr(i, 6) * (1 - dataArr(i, 7))
If Abs(recalculated - dataArr(i, 8)) > 0.01 Then
Debug.Print "Mismatch on row " & i & ": sheet says " & dataArr(i, 8) & _
", recalculated " & Format(recalculated, "0.00")
End If
Next i
Gravando o Array de Volta
Novamente, uma única operação:
ws.Range("A2:I6").Value = dataArr
Evitando Select e Activate
Macros gravadas dependem muito desses comandos (Range("A1").Select e depois Selection.Font.Bold = True), mas eles são desnecessários e lentos — cada .Select força o Excel a redesenhar a tela. Referencie o intervalo ou objeto diretamente:
' Avoid:
ws.Range("A1").Select
Selection.Font.Bold = True
' Prefer:
ws.Range("A1").Font.Bold = True
Considerações de Desempenho
Esses pontos se tornam importantes quando seus dados ultrapassam algumas centenas de linhas:
Application.ScreenUpdating = False ' stop redrawing while the macro runs
Application.Calculation = xlCalculationManual ' pause recalculation
Application.EnableEvents = False ' suppress other macros triggering mid-run
' ... your fast array-based code here ...
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Sempre restaure essas configurações ao final — e envolva a restauração em tratamento de erros para que, caso ocorra uma falha durante a execução, o Excel não fique com a atualização de tela desativada.
Exemplo Prático: o Verificador de Integridade de Pedidos
Este capítulo foi construído para chegar a este ponto:
Option Explicit
Sub VerifyOrderTotals()
Dim ws As Worksheet
Dim dataArr As Variant
Dim lastRow As Long
Dim i As Long
Dim recalculated As Double
Dim issues As String
Set ws = ThisWorkbook.Worksheets("Orders")
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
Application.ScreenUpdating = False
dataArr = ws.Range("A2:I" & lastRow).Value
issues = ""
For i = 1 To UBound(dataArr, 1)
recalculated = dataArr(i, 5) * dataArr(i, 6) * (1 - dataArr(i, 7))
If Abs(recalculated - dataArr(i, 8)) > 0.01 Then
issues = issues & dataArr(i, 1) & ": sheet=" & dataArr(i, 8) & _
", expected=" & Format(recalculated, "0.00") & vbNewLine
End If
Next i
Application.ScreenUpdating = True
If issues = "" Then
MsgBox "All " & UBound(dataArr, 1) & " order totals check out."
Else
MsgBox "Discrepancies found:" & vbNewLine & issues
End If
End Sub
Execute este código na tabela de exemplo e ele deverá informar que todos os cinco totais estão corretos — tente alterar o Total do ORD1002 na planilha para um valor incorreto e execute novamente para ver o alerta ser exibido.
Tarefa
- Copie
VerifyOrderTotalspara sua pasta de trabalho e execute-o nos cinco pedidos de exemplo. - Altere manualmente o
Totalde um pedido na planilha (digite um número obviamente errado) e execute novamente — confirme que a divergência é reportada com oOrder IDcorreto. - Adicione mais dez linhas de dados fictícios de pedidos abaixo da linha 6 e confirme que a macro continua funcionando sem alterações no código — isso é o resultado do uso de
lastRowe processamento por array.
Auxiliar opcional caso prefira gerar as dez linhas extras por código em vez de digitá-las manualmente:
Sub AddTestOrders()
Dim ws As Worksheet
Dim i As Long
Dim r As Long
Set ws = ThisWorkbook.Worksheets("Orders")
r = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row + 1
For i = 1 To 10
ws.Cells(r, 1).Value = "ORD" & (1005 + i)
ws.Cells(r, 2).Value = Date
ws.Cells(r, 3).Value = "Test Customer " & i
ws.Cells(r, 4).Value = "Sample Product"
ws.Cells(r, 5).Value = i
ws.Cells(r, 6).Value = 20 + i
ws.Cells(r, 7).Value = 0.05
ws.Cells(r, 8).Value = i * (20 + i) * (1 - 0.05)
ws.Cells(r, 9).Value = "Pending"
r = r + 1
Next i
End Sub
1. Copiando VerifyOrderTotals
- Digite o
Subexatamente como mostrado na seção 3.5 no módulo da sua pasta de trabalho — sem alterações por enquanto. - Execute uma vez com as cinco linhas originais e confirme que aparece "All 5 order totals check out."
2. Quebrando um Total de propósito
- Escolha qualquer célula de Total de um pedido e digite um número obviamente errado diretamente na planilha (não via código).
- Execute novamente o mesmo
Sub— a mensagem de divergência deve indicar exatamente o ID do pedido, mostrando o valor da planilha e o que a macro recalculou. - Corrija a célula depois, se quiser uma planilha limpa para o próximo passo.
3. Adicionando mais dez linhas
- Basta digitar novos dados de pedidos diretamente nas linhas 7–16 — mesmas nove colunas, quaisquer valores plausíveis.
- Não altere a macro. O
lastRowé recalculado toda vez que oSubroda, e a leitura do array (ws.Range("A2:I" & lastRow).Value) cresce automaticamente — esse é exatamente o ponto demonstrado.
Option Explicit
Sub VerifyOrderTotals()
Dim ws As Worksheet
Dim dataArr As Variant
Dim lastRow As Long
Dim i As Long
Dim recalculated As Double
Dim issues As String
Set ws = ThisWorkbook.Worksheets("Orders")
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
Application.ScreenUpdating = False
dataArr = ws.Range("A2:I" & lastRow).Value
issues = ""
For i = 1 To UBound(dataArr, 1)
recalculated = dataArr(i, 5) * dataArr(i, 6) * (1 - dataArr(i, 7))
If Abs(recalculated - dataArr(i, 8)) > 0.01 Then
issues = issues & dataArr(i, 1) & ": sheet=" & dataArr(i, 8) & _
", expected=" & Format(recalculated, "0.00") & vbNewLine
End If
Next i
Application.ScreenUpdating = True
If issues = "" Then
MsgBox "All " & UBound(dataArr, 1) & " order totals check out."
Else
MsgBox "Discrepancies found:" & vbNewLine & issues
End If
End Sub
Obrigado pelo seu feedback!
Pergunte à IA
Pergunte à IA
Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo