Почему макрос в Excel тормозит, зависает и долго выполняется? Разбираем 9 частых ошибок VBA и показываем, как ускорить код в несколько раз без сложной переделки.
VBA неправильно находит последнюю строку в Excel — причины и безопасные решения
Макрос перезаписывает данные в Excel — 8 ошибок VBA и безопасное решение
Макрос копирует данные неправильно в Excel — 9 ошибок VBA и решения
Почему макрос в Excel работает медленно — 7 ошибок, которые тормозят VBA
Кнопка «Изменить» неактивна в Excel — 5 причин и точные решения
Макрос не запускается в Excel — 7 причин и решения
Ты запускаешь макрос и ожидаешь обычную картину: Excel быстро обработает таблицу, заполнит нужные ячейки, удалит лишнее, перенесёт данные или соберёт отчёт. Задача вроде бы простая. Никакой сложной математики, никаких миллионов строк, ничего такого, из-за чего компьютер должен тяжело вздыхать, как старый принтер в бухгалтерии.
Но проходит несколько секунд, потом ещё десять, потом полминуты. Excel начинает дёргаться, экран мигает, курсор превращается в ожидание, а в заголовке окна иногда появляется страшное «Не отвечает». В этот момент хочется закрыть файл, перезапустить компьютер и сказать, что макросы — это зло.
На самом деле Excel почти всегда ни при чём. В большинстве случаев медленный макрос — это не проблема мощности компьютера, не «старый Office» и не проклятие таблиц. Это результат того, как написан код. Одна и та же задача может выполняться 6 минут или 6 секунд. Разница не в задаче, а в подходе.
Самая большая ловушка VBA в том, что медленный код часто выглядит правильным. Он запускается. Он не падает. Он даёт результат. Просто делает это так, будто несёт ведро воды через весь город, хотя рядом стоит водопровод. И если не понимать, где именно теряется скорость, можно бесконечно добавлять строки, переписывать условия и винить Excel, не трогая настоящую причину.
Почему макрос может быть правильным, но всё равно медленным
VBA работает внутри Excel, а Excel — это не просто таблица с ячейками. Это приложение, которое постоянно обновляет экран, пересчитывает формулы, отслеживает события, хранит буфер обмена, форматирует диапазоны и реагирует на каждое изменение. Когда макрос написан без учёта этих процессов, Excel делает намного больше работы, чем нужно.
Например, код может пройти по 20000 строкам и для каждой строки отдельно обратиться к ячейке, прочитать значение, изменить его, записать обратно, обновить экран, пересчитать формулы и проверить события. С точки зрения пользователя это одна операция. С точки зрения Excel — десятки тысяч маленьких операций.
Именно поэтому первый принцип ускорения простой: нужно уменьшить количество обращений к Excel. Чем меньше макрос дёргает лист, ячейки, экран и формулы, тем быстрее он работает. Хороший VBA-код не «кликает» по таблице как человек. Он берёт данные крупным блоком, обрабатывает их в памяти и возвращает результат одним движением.
Если запомнить только одну мысль из статьи, пусть будет эта: медленный макрос почти всегда делает слишком много лишних действий. Наша задача — убрать лишнее, а не героически ждать, пока Excel справится.
Ошибка №1. Макрос работает с ячейками по одной
Это главный убийца скорости. Чаще всего медленный макрос выглядит логично: цикл идёт по строкам, проверяет каждую ячейку и записывает результат. Для небольших таблиц это работает нормально. Но как только строк становится несколько тысяч, Excel начинает задыхаться.
Проблема в том, что каждое обращение к ячейке — это отдельный контакт VBA с Excel. Макрос не просто берёт число. Он обращается к объектной модели Excel, получает значение, возвращает его, потом снова обращается, чтобы записать результат. Если таких операций 50000, задержка становится заметной.
Плохой вариант обычно выглядит так:
For i = 2 To lastRow
Cells(i, 2).Value = Cells(i, 1).Value * 2*
Next i
Этот код понятен. Он берёт значение из столбца A, умножает на 2 и записывает в столбец B. Но для большой таблицы это медленно, потому что на каждой строке Excel дважды обращается к листу: сначала читает, потом пишет.
Правильный подход — забрать данные в массив, обработать их в памяти и вернуть обратно. В памяти VBA работает намного быстрее, чем при постоянных обращениях к ячейкам.
Dim arr As Variant
Dim resultArr() As Variant
Dim i As Long
arr = Range("A2:A" & lastRow).Value
ReDim resultArr(1 To UBound(arr, 1), 1 To 1)
For i = 1 To UBound(arr, 1)
resultArr(i, 1) = arr(i, 1) * 2*
Next i
Range("B2:B" & lastRow).Value = resultArr
На первый взгляд кода стало больше. Но это как раз тот случай, когда больше строк дают меньше ожидания. Excel получает данные одним блоком и возвращает результат одним блоком. Вместо десятков тысяч обращений — два крупных действия. На больших таблицах разница может быть огромной.
Особенно сильно массивы помогают при очистке данных, проверке условий, массовом заполнении, переносе значений, подготовке отчётов и обработке выгрузок. Если макрос работает дольше минуты и при этом идёт по строкам, первым делом нужно смотреть, можно ли заменить работу с ячейками на массив.
Ошибка №2. В коде остались Select и Activate
Команды Select и Activate часто появляются после записи макроса через встроенный recorder. Excel записывает действия пользователя буквально: выделить ячейку, перейти на лист, выбрать диапазон, вставить значение. Для обучения это полезно, но для рабочего кода — почти всегда плохо.
Когда макрос использует Select, он заставляет Excel реально менять активную ячейку или лист. Это включает обновление интерфейса, лишние действия и зависимость от того, что сейчас открыто на экране. Такой код не только медленнее, но и менее надёжен.
Плохой вариант:
Worksheets("Данные").Activate
Range("A1").Select
Selection.Value = "Готово"
Макрос активирует лист, выделяет ячейку и только потом записывает значение. Для Excel это целая цепочка действий. Хотя на самом деле нужно всего одно: записать значение в конкретную ячейку.
Правильный вариант:
ThisWorkbook.Worksheets("Данные").Range("A1").Value = "Готово"
Код стал короче, быстрее и безопаснее. Он не зависит от активного листа, не двигает курсор, не мигает экраном и сразу выполняет нужное действие. Это базовая привычка, которую стоит выработать: не выбирать ячейки, а обращаться к ним напрямую.
Если в старом макросе много Select и Activate, это первое место для чистки. Обычно после удаления этих команд код становится быстрее, спокойнее и понятнее. Иногда достаточно убрать Select, чтобы макрос перестал «дёргать» экран и начал работать в несколько раз быстрее.
Ошибка №3. Excel постоянно перерисовывает экран
Когда макрос меняет ячейки, Excel по умолчанию показывает это на экране. Если изменений мало, пользователь ничего не замечает. Но если макрос выполняет сотни или тысячи операций, экран начинает мигать, прокручиваться и визуально «жить своей жизнью».
Для пользователя это выглядит как тормоза. На деле Excel тратит ресурсы на то, чтобы показывать промежуточные действия, которые никому не нужны. Нам важен результат, а не театральная постановка «как я обрабатываю таблицу построчно».
Поэтому в начале тяжёлого макроса нужно отключать обновление экрана:
Application.ScreenUpdating = False
А в конце обязательно включать обратно:
Application.ScreenUpdating = True
Но важно не просто добавить эти две строки. Нужно сделать так, чтобы ScreenUpdating возвращался в True даже при ошибке. Иначе после сбоя Excel может остаться в странном состоянии, когда экран не обновляется нормально.
Правильнее использовать безопасную структуру:
Sub FastProcedure()
On Error GoTo ErrHandler*
Application.ScreenUpdating = False*
'здесь выполняется основной код*
SafeExit:
Application.ScreenUpdating = True*
Exit Sub*
ErrHandler:
MsgBox "Ошибка: " & Err.Description*
Resume SafeExit*
End Sub
Такая структура важна для любых макросов, которые отключают настройки Excel. Макрос должен уметь не только быстро начинать работу, но и аккуратно возвращать Excel в нормальное состояние. Это уже не просто ускорение, а культура безопасного кода.
Ошибка №4. Формулы пересчитываются после каждого изменения
Если в файле много формул, медленный макрос может тормозить не из-за самого VBA, а из-за постоянного пересчёта. Макрос изменил одну ячейку — Excel пересчитал формулы. Изменил вторую — снова пересчитал. Изменил тысячу ячеек — получил тысячу лишних пересчётов.
На файлах с большим количеством формул, ВПР, ИНДЕКС, ПОИСКПОЗ, СУММЕСЛИМН, сводными ссылками и внешними связями это превращается в мучение. Макрос вроде бы просто вставляет данные, но Excel после каждого шага пытается обновить весь расчётный мир.
Решение — временно перевести расчёт в ручной режим:
Application.Calculation = xlCalculationManual
А в конце вернуть автоматический режим:
Application.Calculation = xlCalculationAutomatic
Иногда после возврата нужно принудительно пересчитать книгу:
Application.Calculate
Но тут важно понимать задачу. Если макрос вставляет данные, а затем пользователь должен сразу увидеть актуальный результат, пересчёт нужен. Если макрос выполняет промежуточные действия и расчёт будет позже, можно не торопиться.
Безопасный фрагмент выглядит так:
Dim oldCalc As XlCalculation
oldCalc = Application.Calculation
Application.Calculation = xlCalculationManual
'основной код
Application.Calculation = oldCalc
Так лучше, чем просто ставить xlCalculationAutomatic в конце. Почему? Потому что у пользователя до запуска мог быть ручной режим. Если макрос всегда возвращает автоматический, он меняет настройки чужого Excel. Хороший код сначала запоминает исходное состояние, а потом возвращает именно его.
Ошибка №5. События запускают лишние макросы
В Excel есть событийные процедуры: Worksheet_Change, Workbook_Open, Worksheet_Calculate и другие. Они запускаются автоматически при определённых действиях. Это удобно, но может сильно тормозить работу, если основной макрос меняет много ячеек.
Представь, что макрос заполняет 1000 строк. На каждое изменение срабатывает Worksheet_Change. В итоге вместо одного макроса выполняется ещё тысяча дополнительных запусков. Иногда это просто тормозит. Иногда вызывает зацикливание. Иногда Excel зависает так, будто у него закончилась воля к жизни.
Если макрос массово меняет данные, события нужно временно отключать:
Application.EnableEvents = False
И обязательно включать обратно:
Application.EnableEvents = True
Опять же, делать это нужно безопасно, через обработку ошибок. Если макрос отключил события и упал, Excel останется с выключенными событиями. Потом пользователь будет менять ячейки и удивляться, почему автоматические макросы больше не срабатывают.
Нормальный шаблон:
Sub SafeMassUpdate()
On Error GoTo ErrHandler*
Application.EnableEvents = False*
'массовые изменения данных*
SafeExit:
Application.EnableEvents = True*
Exit Sub*
ErrHandler:
MsgBox "Ошибка: " & Err.Description*
Resume SafeExit*
End Sub
Если в твоих файлах есть события, это обязательный пункт. Многие «непонятные тормоза» появляются именно потому, что один макрос запускает другой, тот запускает третий, и Excel честно пытается выполнить весь этот карнавал.
Ошибка №6. Тяжёлые действия выполняются внутри цикла
Очень частая ошибка — делать форматирование, сортировку, фильтрацию, автоподбор ширины или пересчёт внутри цикла. На маленькой таблице это незаметно, но на больших данных такой код становится медленным сразу.
Например, макрос идёт по строкам и на каждой строке применяет формат:
For i = 2 To lastRow
If Cells(i, 1).Value <> "" Then*
Rows(i).Interior.Color = RGB(255, 255, 0)*
Columns("A:F").AutoFit*
End If*
Next i
Здесь AutoFit выполняется на каждой строке. Если строк 5000, Excel 5000 раз подбирает ширину столбцов. Это бессмысленно. Ширину нужно подобрать один раз после завершения всех изменений.
Правильнее так:
For i = 2 To lastRow
If Cells(i, 1).Value <> "" Then*
Rows(i).Interior.Color = RGB(255, 255, 0)*
End If*
Next i
Columns("A:F").AutoFit
То же самое касается сортировки. Нельзя сортировать таблицу после каждой вставленной строки, если можно сначала вставить все строки, а потом отсортировать один раз. Нельзя применять фильтр на каждой итерации, если можно подготовить данные и включить фильтр после обработки.
Хорошее правило: внутри цикла должны оставаться только действия, которые действительно зависят от текущей строки. Всё, что можно сделать один раз до цикла или после цикла, нужно вынести. Это простое правило часто ускоряет макрос сильнее, чем любые хитрые приёмы.
Ошибка №7. Диапазон сильно больше реальных данных
Иногда макрос тормозит не потому, что код плохой, а потому что он работает с огромным диапазоном без необходимости. Например, в таблице 3000 строк, а код обрабатывает A1:Z100000. Или формулы протянуты на 50000 строк, хотя реальных данных всего 800.
Excel честно выполняет работу по всему указанному диапазону. Он не знает, что ты «на всякий случай» взял больше. Для него это конкретная команда. Поэтому лишние строки и столбцы превращаются в лишнее время.
Плохой вариант:
Range("A2:Z100000").ClearContents
Если реальная таблица занимает A2:F3000, такой код чистит намного больше, чем нужно. Иногда это допустимо, но для производительности и безопасности лучше работать с реальными границами.
Сначала определяем последнюю строку и последний столбец:
Dim lastRow As Long
Dim lastCol As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
Потом строим точный диапазон:
Dim workRange As Range
Set workRange = ws.Range(ws.Cells(2, 1), ws.Cells(lastRow, lastCol))
workRange.ClearContents
Так макрос не трогает лишнее. Это ускоряет выполнение и снижает риск случайно очистить соседние данные, формулы или служебные блоки.
Но важно правильно выбирать столбец для lastRow. Если столбец A ненадёжный, бери тот, где данные есть всегда: номер документа, дата, ID, артикул. Неправильный lastRow — отдельная большая проблема, и она часто становится причиной не только тормозов, но и испорченных отчётов.
Ошибка №8. Copy/Paste используется там, где достаточно Value
Copy/Paste — удобная команда, но для VBA она часто слишком тяжёлая. Она использует буфер обмена, переносит не только значения, но и формат, формулы, проверки, ширину, иногда лишние элементы. Если задача — просто перенести значения, Copy/Paste избыточен.
Плохой вариант:
wsSource.Range("A2:F" & lastRow).Copy
wsTarget.Range("A2").PasteSpecial Paste:=xlPasteValues
Он рабочий, но не самый быстрый. Если нужно перенести только значения, лучше сделать прямое присваивание:
wsTarget.Range("A2").Resize(sourceRange.Rows.Count, sourceRange.Columns.Count).Value = sourceRange.Value
Такой код быстрее, чище и не трогает буфер обмена. После него не остаётся мигающей рамки вокруг скопированного диапазона, не нужно очищать CutCopyMode, и меньше шансов получить странное поведение при параллельной работе с Excel.
Copy/Paste имеет смысл, когда нужно перенести формат, ширину столбцов, примечания или формулы в исходном виде. Но в большинстве отчётов нужно именно значение. Особенно если данные приходят из грязной выгрузки, а на листе назначения уже есть свой шаблон оформления.
Разделяй данные и оформление. Данные лучше переносить через Value, оформление — через заранее подготовленный шаблон. Это быстрее, аккуратнее и намного надёжнее.
Ошибка №9. Нет измерения времени выполнения
Многие пытаются ускорять макрос на глаз. Кажется, что тормозит цикл. Потом кажется, что формулы. Потом кажется, что Copy/Paste. В итоге код переписывается хаотично, а настоящая причина может остаться на месте.
Нужно измерять. Самый простой способ — Timer.
Dim t As Double
t = Timer
'здесь выполняется код
MsgBox "Время выполнения: " & Format(Timer - t, "0.00") & " сек."
Если макрос большой, можно ставить промежуточные замеры после ключевых блоков: загрузка данных, обработка массива, запись результата, форматирование, сортировка. Тогда сразу видно, где именно теряется время.
Пример:
Dim t As Double
t = Timer
arr = ws.Range("A2:F" & lastRow).Value
Debug.Print "Загрузка массива: " & Format(Timer - t, "0.00")
t = Timer
'обработка данных
Debug.Print "Обработка: " & Format(Timer - t, "0.00")
t = Timer
ws.Range("A2:F" & lastRow).Value = arr
Debug.Print "Запись результата: " & Format(Timer - t, "0.00")
Debug.Print выводит данные в окно Immediate в редакторе VBA. Это удобно для отладки, потому что не нужно каждый раз показывать пользователю сообщения. Для рабочих макросов можно оставить только итоговое сообщение или вести журнал выполнения на отдельном листе.
Измерение времени — это не украшение. Это способ перестать гадать. Иногда выясняется, что 90% времени занимает не цикл, а один AutoFit в конце. Или не обработка, а пересчёт формул. Без замеров такие вещи легко пропустить.
Универсальный шаблон быстрого макроса
Теперь соберём рабочий шаблон, который можно использовать как основу. Он запоминает старые настройки Excel, отключает лишнее на время работы, обрабатывает данные через массив и возвращает Excel в нормальное состояние даже при ошибке.
Sub FastMacroTemplate()
Dim ws As Worksheet*
Dim lastRow As Long*
Dim arr As Variant*
Dim i As Long*
Dim oldCalc As XlCalculation*
Dim t As Double*
On Error GoTo ErrHandler*
t = Timer*
Set ws = ThisWorkbook.Worksheets("Данные")*
oldCalc = Application.Calculation*
Application.ScreenUpdating = False*
Application.EnableEvents = False*
Application.Calculation = xlCalculationManual*
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row*
If lastRow < 2 Then*
MsgBox "Нет данных для обработки."*
GoTo SafeExit*
End If*
arr = ws.Range("A2:A" & lastRow).Value*
For i = 1 To UBound(arr, 1)*
If Trim(arr(i, 1)) <> "" Then*
arr(i, 1) = UCase(arr(i, 1))*
End If*
Next i*
ws.Range("A2:A" & lastRow).Value = arr*
MsgBox "Готово. Время выполнения: " & Format(Timer - t, "0.00") & " сек."*
SafeExit:
Application.ScreenUpdating = True*
Application.EnableEvents = True*
Application.Calculation = oldCalc*
Exit Sub*
ErrHandler:
MsgBox "Ошибка: " & Err.Description*
Resume SafeExit*
End Sub
Этот шаблон не нужно копировать бездумно. Его нужно адаптировать под свою задачу: поменять имя листа, опорный столбец, диапазон, логику обработки массива. Но сама структура правильная: настройки отключаются безопасно, данные обрабатываются крупным блоком, Excel возвращается в исходное состояние.
Обрати внимание на oldCalc. Мы не просто включаем автоматический пересчёт в конце, а возвращаем тот режим, который был до запуска. Это уважение к файлу и пользователю. Если у человека стоял ручной пересчёт, макрос не должен самовольно менять его привычную настройку.
Реальный пример: ускоряем обработку статусов
Допустим, есть таблица заявок. В столбце A — номер заявки, в столбце B — статус. Нужно пройти по статусам и заменить «new» на «Новая», «done» на «Готово», «cancel» на «Отмена». Медленный вариант будет ходить по каждой ячейке на листе. Быстрый — обработает массив.
Медленный вариант:
Sub SlowStatusUpdate()
Dim ws As Worksheet*
Dim lastRow As Long*
Dim i As Long*
Set ws = ThisWorkbook.Worksheets("Данные")*
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row*
For i = 2 To lastRow*
If ws.Cells(i, "B").Value = "new" Then ws.Cells(i, "B").Value = "Новая"*
If ws.Cells(i, "B").Value = "done" Then ws.Cells(i, "B").Value = "Готово"*
If ws.Cells(i, "B").Value = "cancel" Then ws.Cells(i, "B").Value = "Отмена"*
Next i*
End Sub
Работает? Да. Быстро? На большой таблице — нет. Каждая проверка обращается к ячейке. Причём в одной строке код может обратиться к одной и той же ячейке несколько раз.
Быстрый вариант:
Sub FastStatusUpdate()
Dim ws As Worksheet*
Dim lastRow As Long*
Dim arr As Variant*
Dim i As Long*
On Error GoTo ErrHandler*
Application.ScreenUpdating = False*
Application.EnableEvents = False*
Application.Calculation = xlCalculationManual*
Set ws = ThisWorkbook.Worksheets("Данные")*
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row*
If lastRow < 2 Then GoTo SafeExit*
arr = ws.Range("B2:B" & lastRow).Value*
For i = 1 To UBound(arr, 1)*
Select Case LCase(Trim(arr(i, 1)))*
Case "new"*
arr(i, 1) = "Новая"*
Case "done"*
arr(i, 1) = "Готово"*
Case "cancel"*
arr(i, 1) = "Отмена"*
End Select*
Next i*
ws.Range("B2:B" & lastRow).Value = arr*
SafeExit:
Application.ScreenUpdating = True*
Application.EnableEvents = True*
Application.Calculation = xlCalculationAutomatic*
Exit Sub*
ErrHandler:
MsgBox "Ошибка: " & Err.Description*
Resume SafeExit*
End Sub
Здесь данные из столбца B один раз забираются в массив, обрабатываются внутри VBA и одним движением возвращаются обратно. На больших таблицах разница будет очень заметной. Плюс код стал чище: вместо нескольких If используется Select Case, а значения приводятся к нижнему регистру и очищаются от лишних пробелов.
Как понять, что макрос действительно стал быстрее
После оптимизации важно не просто почувствовать, что «вроде быстрее», а измерить. Запусти старую версию и новую на копии одного и того же файла. Не на разных данных, не на разных таблицах, не «примерно похоже», а на одинаковом наборе.
Сравни три вещи: общее время выполнения, стабильность результата и отсутствие побочных эффектов. Быстрый макрос не должен ради скорости ломать формат, пропускать строки или оставлять Excel с выключенными событиями. Ускорение без безопасности — не победа, а новая проблема в красивой упаковке.
Хороший результат выглядит так: макрос стал быстрее, данные совпадают, формулы не испорчены, Excel после выполнения работает нормально, настройки возвращены, пользователь понимает, сколько строк обработано и сколько времени заняла операция.
Если после оптимизации файл начал работать быстрее, но появились странные ошибки, значит оптимизация была слишком грубой. Например, отключили пересчёт, но не пересчитали результат. Или перенесли значения через массив, но потеряли формат, который был нужен. Поэтому ускорение всегда нужно проверять на реальном сценарии.
Что делать, если макрос всё равно медленный
Если ты уже убрал Select, отключил экран, события и пересчёт, перешёл на массивы, но макрос всё равно работает медленно, нужно искать более глубокую причину. Возможно, проблема в формулах файла, внешних ссылках, сводных таблицах, условном форматировании, огромном количестве стилей или слишком тяжёлой структуре книги.
Иногда Excel тормозит не из-за VBA, а из-за самого файла. Например, на листе десятки тысяч правил условного форматирования, огромный UsedRange, внешние связи на недоступные файлы или формулы протянуты далеко вниз. Макрос только запускает процесс, а тормозит вся книга.
В таком случае нужно чистить файл: удалять лишнее форматирование, сокращать диапазоны формул, проверять внешние ссылки, пересобирать условное форматирование, сохранять книгу в нормальном формате .xlsm и иногда переносить данные в новый чистый файл. Это уже не только VBA, а общая гигиена Excel.
Но начинать всё равно стоит с кода. В 80–90% случаев главные тормоза находятся именно там: ячейки по одной, Select, экран, пересчёт, события, лишние действия внутри цикла и завышенные диапазоны.
В Телеграме я выкладываю готовые файлы и шаблоны VBA, которые можно использовать как основу:
быстрые циклы, работа через массивы, безопасные шаблоны с возвратом настроек Excel, ускорение отчётов и готовые макросы для реальных задач.
Если хочешь не только читать разбор, а забирать рабочие инструменты — подписывайся.
Итог
Медленный макрос — это не приговор и не обязательная плата за автоматизацию. Чаще всего это набор типовых ошибок: работа с ячейками по одной, Select и Activate, постоянная перерисовка экрана, пересчёт формул, события, тяжёлые действия внутри цикла, слишком большой диапазон, лишний Copy/Paste и отсутствие измерений.
Исправляются эти ошибки не магией, а дисциплиной. Явно указывать листы. Работать с массивами. Отключать лишние процессы на время выполнения. Возвращать настройки Excel после завершения. Измерять время. Не делать внутри цикла то, что можно сделать один раз.
Когда макрос написан правильно, Excel перестаёт выглядеть слабым. Он спокойно обрабатывает тысячи и десятки тысяч строк. И то, что раньше занимало минуты, начинает выполняться за секунды. Именно ради этого макросы и нужны: не чтобы ждать ещё один медленный процесс, а чтобы наконец перестать делать руками то, что машина может выполнить быстрее.