Khi các macro Excel của bạn ngày càng trở nên mạnh mẽ và phức tạp, bạn có thể thấy rằng chúng giảm hiệu suất. Khi thảo luận về macro, từ hiệu suất thường đồng nghĩa với tốc độ . Tốc độ là tốc độ các thủ tục VBA của bạn thực hiện các tác vụ dự định của chúng. Sau đây là mười cách để giúp giữ cho macro Excel của bạn chạy ở mức hiệu suất tối ưu.
Tạm dừng tính toán trang tính
Bạn có biết rằng mỗi khi một ô ảnh hưởng đến bất kỳ công thức nào trong bảng tính của bạn bị thay đổi hoặc thao tác, Excel sẽ tính toán lại toàn bộ trang tính? Trong các trang tính có một lượng lớn công thức, hành vi này có thể làm chậm các macro của bạn.
Bạn có thể sử dụng thuộc tính Application.Calculation để yêu cầu Excel chuyển sang chế độ tính toán thủ công. Khi sổ làm việc ở chế độ tính toán thủ công, sổ làm việc sẽ không tính toán lại cho đến khi bạn kích hoạt phép tính một cách rõ ràng bằng cách nhấn phím F9.
Đặt Excel vào chế độ tính toán thủ công, chạy mã của bạn, sau đó chuyển trở lại chế độ tính toán tự động.
Sub Macro1 ()
Application.Calculation = xlCalculationManual
'Đặt mã macro của bạn ở đây
Application.Calculation = xlCalculationAutomatic
Kết thúc Sub
Đặt chế độ tính toán trở lại xlCalculationAutomatic sẽ tự động kích hoạt tính toán lại trang tính, vì vậy không cần nhấn phím F9 sau khi macro của bạn chạy.
Tắt cập nhật màn hình trang tính
Bạn có thể nhận thấy rằng khi macro của bạn chạy, màn hình của bạn nhấp nháy khá nhiều. Hiện tượng nhấp nháy này là do Excel đang cố gắng vẽ lại màn hình để hiển thị trạng thái hiện tại của trang tính. Thật không may, mỗi lần Excel vẽ lại màn hình, nó sẽ chiếm tài nguyên bộ nhớ.
Bạn có thể sử dụng thuộc tính Application.ScreenUpdating để tắt cập nhật màn hình cho đến khi macro của bạn hoàn tất. Việc tắt cập nhật màn hình sẽ tiết kiệm thời gian và tài nguyên, cho phép macro của bạn chạy nhanh hơn một chút. Sau khi mã macro của bạn chạy xong, bạn có thể bật lại tính năng cập nhật màn hình.
Sub Macro1 ()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = Sai
'Đặt mã macro của bạn ở đây
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Kết thúc Sub
Sau khi bạn đặt thuộc tính ScreenUpdating trở lại True, Excel sẽ tự động kích hoạt vẽ lại màn hình.
Tắt cập nhật thanh trạng thái
Thanh trạng thái Excel, xuất hiện ở cuối cửa sổ Excel, thường hiển thị tiến trình của các hành động nhất định trong Excel. Nếu macro của bạn đang hoạt động với nhiều dữ liệu, thanh trạng thái sẽ chiếm một số tài nguyên.
Điều quan trọng cần lưu ý là tắt cập nhật màn hình tách biệt với tắt hiển thị thanh trạng thái. Thanh trạng thái sẽ tiếp tục được cập nhật ngay cả khi bạn tắt cập nhật màn hình. Bạn có thể sử dụng thuộc tính Application.DisplayStatusBar để tạm thời vô hiệu hóa mọi cập nhật thanh trạng thái, cải thiện hơn nữa hiệu suất của macro của bạn:
Sub Macro1 ()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = Sai
Application.DisplayStatusBar = Sai
'Đặt mã macro của bạn ở đây
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Kết thúc Sub
Yêu cầu Excel bỏ qua các sự kiện
Bạn có thể triển khai macro dưới dạng thủ tục sự kiện, yêu cầu Excel chạy mã nhất định khi trang tính hoặc sổ làm việc thay đổi.
Đôi khi, các macro tiêu chuẩn thực hiện các thay đổi sẽ kích hoạt quy trình sự kiện. Ví dụ: nếu bạn có macro chuẩn thao tác với một số ô trên Trang tính1, mỗi khi ô trên trang tính đó bị thay đổi, macro của bạn phải tạm dừng trong khi sự kiện Worksheet_Change chạy.
Bạn có thể thêm một mức tăng hiệu suất khác bằng cách sử dụng thuộc tính EnableEvents để yêu cầu Excel bỏ qua các sự kiện trong khi macro của bạn chạy.
Đặt thuộc tính EnableEvents thành False trước khi chạy macro của bạn. Sau khi mã macro của bạn chạy xong, bạn có thể đặt thuộc tính EnableEvents trở lại True.
Sub Macro1 ()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = Sai
Application.DisplayStatusBar = Sai
Application.EnableEvents = Sai
'Đặt mã macro của bạn ở đây
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.EnableEvents = True
Kết thúc Sub
Ẩn ngắt trang
Mỗi khi macro của bạn sửa đổi số hàng, sửa đổi số cột hoặc thay đổi thiết lập trang của trang tính, Excel buộc phải mất thời gian tính toán lại các ngắt trang được hiển thị trên trang tính.
Bạn có thể tránh hành vi này bằng cách chỉ cần ẩn ngắt trang trước khi bắt đầu macro của mình.
Đặt thuộc tính trang tính DisplayPageBreaks thành Sai để ẩn ngắt trang. Nếu bạn muốn tiếp tục hiển thị ngắt trang sau khi macro của bạn chạy, hãy đặt thuộc tính trang tính DisplayPageBreaks trở lại True.
Sub Macro1 ()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = Sai
Application.DisplayStatusBar = Sai
Application.EnableEvents = Sai
Activesheet.DisplayPageBreaks = Sai
'Đặt mã macro của bạn ở đây
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.EnableEvents = True
Activesheet.DisplayPageBreaks = True
Kết thúc Sub
Tạm dừng cập nhật bảng tổng hợp
Nếu macro của bạn thao tác với bảng tổng hợp có chứa nguồn dữ liệu lớn, bạn có thể gặp phải hiệu suất kém khi thực hiện những việc như thêm động hoặc di chuyển trường tổng hợp.
Bạn có thể cải thiện hiệu suất của macro của mình bằng cách tạm ngừng tính toán lại bảng tổng hợp cho đến khi tất cả các thay đổi trường tổng hợp đã được thực hiện. Chỉ cần đặt thuộc tính PivotTable.ManualUpdate thành True để hoãn tính toán lại, chạy mã macro của bạn, sau đó đặt thuộc tính PivotTable.ManualUpdate trở lại False để kích hoạt tính toán lại.
Sub Macro1 ()
ActiveSheet.PivotTables ("PivotTable1"). ManualUpdate = True
'Đặt mã macro của bạn ở đây
ActiveSheet.PivotTables ("PivotTable1"). ManualUpdate = False
Kết thúc Sub
Chỉ đạo xóa sao chép và dán
Điều quan trọng cần nhớ là mặc dù Macro Recorder tiết kiệm thời gian bằng cách viết mã VBA cho bạn, nhưng không phải lúc nào nó cũng viết mã hiệu quả nhất. Một ví dụ điển hình là cách Macro Recorder ghi lại bất kỳ hành động sao chép và dán nào bạn thực hiện trong khi ghi.
Bạn có thể tăng nhẹ các macro của mình bằng cách cắt bỏ phần trung gian và thực hiện sao chép trực tiếp từ một ô sang ô đích. Mã thay thế này sử dụng đối số Đích để bỏ qua khay nhớ tạm và sao chép trực tiếp nội dung của ô A1 sang ô B1.
Phạm vi ("A1"). Sao chép Đích: = Phạm vi ("B1")
Nếu bạn chỉ cần sao chép các giá trị (không phải định dạng hoặc công thức), bạn có thể cải thiện hiệu suất hơn nữa bằng cách tránh tất cả các phương pháp Sao chép cùng nhau. Chỉ cần đặt giá trị của ô đích thành cùng giá trị được tìm thấy trong ô nguồn. Phương pháp này nhanh hơn khoảng 25 lần so với sử dụng phương pháp Sao chép:
Phạm vi ("B1"). Giá trị = Phạm vi ("A1"). Giá trị
Nếu bạn chỉ cần sao chép công thức từ ô này sang ô khác (không phải giá trị hoặc định dạng), bạn có thể đặt công thức của ô đích thành công thức giống như trong ô nguồn:
Phạm vi ("B1"). Công thức = Phạm vi ("A1"). Công thức
Sử dụng câu lệnh With
Khi ghi macro, bạn thường sẽ thao tác với cùng một đối tượng nhiều hơn một lần. Bạn có thể tiết kiệm thời gian và cải thiện hiệu suất bằng cách sử dụng câu lệnh With để thực hiện một số hành động trên một đối tượng nhất định trong một lần chụp.
Câu lệnh With được sử dụng trong ví dụ sau yêu cầu Excel áp dụng tất cả các thay đổi định dạng cùng một lúc:
Với Phạm vi ("A1"). Phông chữ
.Bold = True
.Italic = Đúng
.Underline = xlUnderlineStyleSingle
Kết thúc với
Tập thói quen phân nhóm các hành động vào câu lệnh With sẽ không chỉ giữ cho macro của bạn chạy nhanh hơn mà còn giúp bạn đọc mã macro của bạn dễ dàng hơn.
Tránh phương pháp Chọn
Macro Recorder thích sử dụng phương pháp Chọn để chọn các đối tượng một cách rõ ràng trước khi thực hiện các hành động trên chúng. Nói chung không cần phải chọn các đối tượng trước khi làm việc với chúng. Trên thực tế, bạn có thể cải thiện đáng kể hiệu suất macro bằng cách không sử dụng phương pháp Chọn.
Sau khi ghi macro của bạn, hãy tạo thói quen thay đổi mã đã tạo để loại bỏ các phương pháp Chọn. Trong trường hợp này, mã được tối ưu hóa sẽ giống như sau:
Trang tính ("Trang 1"). Phạm vi ("A1"). Công thứcR1C1 = "1000"
Trang tính ("Trang tính2"). Phạm vi ("A1"). Công thứcR1C1 = "1000"
Trang tính ("Trang tính 3"). Phạm vi ("A1"). Công thứcR1C1 = "1000"
Lưu ý rằng không có gì đang được chọn. Mã chỉ đơn giản sử dụng cấu trúc phân cấp đối tượng để áp dụng các hành động cần thiết.
Giới hạn các chuyến đi đến trang tính
Một cách khác để tăng tốc macro của bạn là giới hạn số lần bạn tham chiếu dữ liệu trang tính trong mã của mình. Việc lấy dữ liệu từ trang tính luôn kém hiệu quả hơn là từ bộ nhớ. Điều đó có nghĩa là, các macro của bạn sẽ chạy nhanh hơn nhiều nếu chúng không phải tương tác nhiều lần với trang tính.
Ví dụ: mã đơn giản sau đây buộc VBA liên tục quay trở lại Trang tính (“Trang 1”). Phạm vi (“A1”) để nhận số cần thiết cho phép so sánh đang được thực hiện trong câu lệnh If:
Đối với ReportMonth = 1 đến 12
Nếu Phạm vi ("A1"). Giá trị = Báo cáo Tháng Sau đó
MsgBox 1000000 / ReportMonth
Kết thúc nếu
Báo cáo tháng tiếp theo
Một phương pháp hiệu quả hơn nhiều là lưu giá trị trong Trang tính (“Sheet1”). Phạm vi (“A1”) vào một biến có tên MyMonth. Bằng cách này, mã tham chiếu đến biến MyMonth thay vì trang tính:
Làm mờ MyMonth dưới dạng Số nguyên
MyMonth = Phạm vi ("A1"). Giá trị
Đối với ReportMonth = 1 đến 12
If MyMonth = ReportMonth thì
MsgBox 1000000 / ReportMonth
Kết thúc nếu
Báo cáo tháng tiếp theo
Cân nhắc việc tận dụng các biến để làm việc với dữ liệu trong bộ nhớ thay vì tham chiếu trực tiếp đến trang tính.
Tránh tham khảo quá nhiều
Khi gọi một phương thức hoặc thuộc tính của một đối tượng, nó cần phải thông qua giao diện IDispatch của thành phần OLE. Cuộc gọi đến các thành phần OLE này mất thời gian, do đó việc giảm số lượng tham chiếu đến các thành phần OLE có thể cải thiện tốc độ của mã macro.
Để gọi các thuộc tính hoặc phương thức đối tượng, phương thức biểu diễn của Object.Method thường được sử dụng, nghĩa là "." biểu tượng được sử dụng để gọi các thuộc tính và phương thức.
Do đó, số lượng lệnh gọi phương thức hoặc thuộc tính có thể được đánh giá theo số lượng ký hiệu ".". Càng ít dấu "." biểu tượng, mã chạy càng nhanh.
Ví dụ: câu lệnh sau bao gồm 3 ký hiệu ".".
ThisWorkbook.Sheet1.Range("A1").Value = 100
Câu lệnh sau chỉ có một ký hiệu ".".
Activewindow.Top = 100
Dưới đây là một số thủ thuật để giảm số lượng ký hiệu "." để chạy nhanh hơn
Đầu tiên, khi bạn cần tham chiếu nhiều lần đến cùng một đối tượng, bạn có thể đặt đối tượng đó thành một biến để giảm số lượng lệnh gọi. Ví dụ: đoạn mã sau yêu cầu hai cuộc gọi trên mỗi dòng.
ThisWorkbook.Sheets("Sheet1").Cells(1, 1) = 100
ThisWorkbook.Sheets("Sheet1").Cells(2, 1) = 200
ThisWorkbook.Sheets("Sheet1").Cells(3, 1) = 300
Vì đối tượng Sheets("Sheet1") cần được tham chiếu nhiều lần nên trước tiên nó có thể được đặt thành một biến sht để mỗi mã chỉ cần được gọi một lần.
Set sht = ThisWorkbook.Sheets("Sheet1")
sht.Cells(1, 1) = 100
sht.Cells(2, 1) = 200
sht.Cells(3, 1) = 300
Thứ hai, nếu bạn không muốn khai báo biến tạm thời sht, bạn cũng có thể sử dụng câu lệnh With đã đề cập trước đó. Như thể hiện trong ví dụ sau:
With ThisWorkbook.Sheets("Sheet1")
.Cells(1, 1) = 100
.Cells(2, 1) = 200
.Cells(3, 1) = 300
End With
Thứ ba, khi có nhiều vòng lặp, hãy cố gắng giữ các thuộc tính và phương thức bên ngoài vòng lặp. Khi sử dụng lại giá trị thuộc tính của cùng một đối tượng trong vòng lặp, trước tiên bạn có thể gán giá trị thuộc tính cho một biến được chỉ định bên ngoài vòng lặp, sau đó sử dụng biến trong vòng lặp, điều này có thể đạt được tốc độ nhanh hơn. Như thể hiện trong ví dụ sau:
For i = 1 To 1000
ThisWorkbook.Sheets("Sheet1").Cells(1, 1) = Cells(1, 2).Value
ThisWorkbook.Sheets("Sheet1").Cells(2, 1) = Cells(1, 2).Value
ThisWorkbook.Sheets("Sheet1").Cells(3, 1) = Cells(1, 2).Value
Next i
Mỗi vòng lặp trong ví dụ này lấy thuộc tính Giá trị của ô Ô (1,2). Nếu bạn gán thuộc tính Giá trị của Ô (1.2) cho một biến trước khi vòng lặp bắt đầu, bạn sẽ chạy nhanh hơn. Như thể hiện trong ví dụ sau:
tmp = Cells(1, 2).Value
For i = 1 To 1000
ThisWorkbook.Sheets("Sheet1").Cells(1, 1) = tmp
ThisWorkbook.Sheets("Sheet1").Cells(2, 1) = tmp
ThisWorkbook.Sheets("Sheet1").Cells(3, 1) = tmp
Next i
Đoạn mã trên gọi ThisWorkbook.Sheets("Sheet1") mỗi khi nó lặp lại. Bạn có thể thực hiện việc này nhanh hơn bằng cách sử dụng câu lệnh With để di chuyển cuộc gọi đến ThisWorkbook.Sheets("Sheet1") bên ngoài vòng lặp. Như thể hiện trong ví dụ sau:
tmp = Cells(1, 2).Value
With ThisWorkbook.Sheets("Sheet1")
For i = 1 To 1000
.Cells(1, 1) = tmp
.Cells(2, 1) = tmp
.Cells(3, 1) = tmp
Next i
End With
Tránh sử dụng các loại biến thể
Những người mới bắt đầu thường thích sử dụng các biến kiểu Variant, có ưu điểm là ít phức tạp hơn vì có thể sử dụng bất kỳ loại dữ liệu nào mà không gặp vấn đề tràn bộ nhớ nếu dữ liệu quá lớn đối với kiểu dữ liệu Integer hoặc Long. Tuy nhiên, dữ liệu loại Varienmt yêu cầu nhiều dung lượng bộ nhớ hơn các loại được chỉ định khác (2 byte cho dữ liệu Số nguyên, 4 byte cho dữ liệu Dài và 16 byte cho dữ liệu Biến thể), VBA yêu cầu nhiều thời gian hơn để xử lý dữ liệu loại Biến thể so với các loại được chỉ định khác Dữ liệu. Như ví dụ sau đây cho thấy.
Sub VariantTest()
Dim i As Long
Dim ix As Integer, iy As Integer, iz As Integer
Dim vx As Variant, vy As Variant, vz As Variant
Dim tm As Date
vx = 100: vy = 50
tm = Timer
For i = 1 To 1000000
vz = vx * vy
vz = vx + vy
vz = vx - vy
vz = vx / vy
Next i
Debug.Print "Variant types take " & Format((Timer - tm), "0.00000") & " seconds"
ix = 100: iy = 50
tm = Timer
For i = 1 To 1000000
iz = ix * iy
iz = ix + iy
iz = ix - iy
iz = ix / iy
Next i
Debug.Print "Integer types take " & Format((Timer - tm), "0.00000") & " seconds"
End Sub
Trong đoạn mã trên, các dòng 8 đến 13 thực hiện 1 triệu phép tính cộng, trừ, nhân và chia các biến Biến thể và các dòng 17 đến 22 thực hiện 1 triệu phép tính cộng, trừ, nhân và chia các biến Số nguyên. Trên máy tính của tôi, thao tác của biến Variant mất khoảng 0,09375 giây, trong khi thao tác của biến Integer mất khoảng 0,03125 giây. Kết quả có thể khác nhau tùy theo từng máy tính, nhưng biến Variant chậm hơn đáng kể so với biến Integer .
Vì lý do này, bạn nên tránh sử dụng các biến Variant khi bạn có thể sử dụng rõ ràng kiểu dữ liệu đã chỉ định .