Как ускорить for в vba excel

Хитрости »

20 Январь 2016              61488 просмотров


Рано или поздно у пишущих на Visual Basic for Applications возникает проблема — код хоть и облегчает жизнь и делает все автоматически, но очень долго. В этой статье я решил собрать несколько простых рекомендаций, которые помогут ускорить работу кода VBA, при этом в некоторых случаях весьма внушительно — в десятки, а то и больше, раз. Основной упор в статье сделан на начинающих, поэтому в начале статьи приводятся самые простые методы оптимизации. Более «глубокие» решения по оптимизации кода приведены в конце статьи, т.к. для применения данных решений необходим достаточный опыт работы в VB и сходу такие методы оптимизации кому-то могут быть непонятны.

  1. Если в коде есть много всяких Activate и Select, тем более в циклах — следует немедленно от них избавиться. Как это сделать я писал в статье: Select и Activate — зачем нужны и нужны ли?
  2. Обязательно на время выполнения кода отключить:
    • автоматический пересчет формул. Чтобы формулы не пересчитывались при каждой манипуляции на листе во время выполнения кода — это может дико тормозить код, если формул много:
      Application.Calculation = xlCalculationManual

      Если во время кода все же нужно пересчитывать какие-то диапазоны, то можно пересчитывать только их:

      Range("A1:C60").Calculate
    • обновление экрана, чтобы действия по изменению значений ячеек и пр. не мелькали. Зачем это надо? Т.к. все эти действия обращаются к графическому процессору и заставляют его трудиться для перерисовки экрана — это может значительно тормозить код:
      Application.ScreenUpdating = False
    • На всякий случай отключаем отслеживание событий. Нужно для того, чтобы Excel не выполнял никаких событийных процедур, которые могут быть в листе, в котором производятся изменения. Как правило это события изменения ячеек, активации листов и пр.:
      Application.EnableEvents = False
    • Если книга выводилась на печать или выводится на печать в процессе выполнения кода, то лучше убрать разбиение на печатные страницы.
      ActiveWorkbook.ActiveSheet.DisplayPageBreaks = False

      если печать производится внутри кода, то эту строку желательно вставить сразу после строки, выводящей лист на печать(при условии, что печать не происходит в цикле. В этом случае — по завершению цикла печати).
      Я советую всегда отключать разбиение на страницы, т.к. это может тормозить весьма значительно, т.к. заставляет при любом изменении на листах обращаться к принтеру и переопределять кол-во и размер печатных страниц. А это порой очень не быстро.

    • На всякий случай можно отключить отображение информации в строке статуса Excel(в каких случаях там вообще отображается информация и зачем можно узнать в статье: Отобразить процесс выполнения). Хоть это и не сильно поедает ресурсы — иногда может все же ускорить работу кода:
      Application.StatusBar = False

    Главное, что следует помнить — все эти свойства необходимо включить обратно после работы кода. Иначе могут быть проблемы с работой внутри Excel. Например, если забыть включить автопересчет формул — большинство формул будут пересчитывать исключительно принудительным методом — после нажатия сочетания клавиш Shift+F9. А если забыть отключить обновление экрана — то есть шанс заблокировать себе возможность работы на листах и книгах. Хотя по умолчанию свойство ScreenUpdating и должно возвращаться в True, если было отключено внутри процедуры — лучше не надеяться на это и привыкать возвращать все свойства на свои места принудительно. По сути все это сведется к нескольким строкам:

    'Возвращаем обновление экрана
    Application.ScreenUpdating = True
    'Возвращаем автопересчет формул
    Application.Calculation = xlCalculationAutomatic
    'Включаем отслеживание событий
    Application.EnableEvents = True

    Как такой код выглядит на практике. Предположим, надо записать в цикле в 10 000 строк значения:

    Sub TestOptimize()
    'отключаем обновление экрана
    Application.ScreenUpdating = False
    'Отключаем автопересчет формул
    Application.Calculation = xlCalculationManual
    'Отключаем отслеживание событий
    Application.EnableEvents = False
    'Отключаем разбиение на печатные страницы
    ActiveWorkbook.ActiveSheet.DisplayPageBreaks = False
     
    'Непосредственно код заполнения ячеек
    Dim lr As Long
    For lr = 1 To 10000
        Cells(lr, 1).Value = lr 'для примера просто пронумеруем строки
    Next
     
    'Возвращаем обновление экрана
    Application.ScreenUpdating = True
    'Возвращаем автопересчет формул
    Application.Calculation = xlCalculationAutomatic
    'Включаем отслеживание событий
    Application.EnableEvents = True
    End Sub

    Разрывы печатных страниц можно не возвращать — они тормозят работу в любом случае.

  3. Следует избегать циклов, вроде Do While для поиска последней ячейки. Часто такую ошибку совершают начинающие. Куда эффективнее и быстрее вычислять последнюю ячейку на всем листе или в конкретном столбце без этого тормозного цикла Do While. Я обычно использую
    lLastRow = Cells(Rows.Count,1).End(xlUp).Row

    другие варианты определения последней ячейки я детально описывал в статье: Как определить последнюю ячейку на листе через VBA?

Для более опытных пользователей VBA я приведу несколько решений по оптимизации кодов в различных ситуациях:

  • Самая хорошая оптимизация кода, если приходится работать с ячейками листа напрямую, обрабатывать их и, возможно, изменять значения, то быстрее все обработки делать в массиве и разом выгружать на листе. Например, код выше по заполнению ячеек номерами будет в этом случае выглядеть так:
    Sub TestOptimize_Array()
    'Непосредственно код заполнения ячеек
    Dim arr, lr As Long
    'запоминаем в массив одним махом все значения 10000 строк первого столбца
    arr = Cells(1, 1).Resize(10000).Value
    'если нужно заполнение для двух и более столбцов
    'arr = Cells(1, 1).Resize(10000, 2).Value
    'или 
    'arr = Range(Cells(1, 1),Cells(10000, 2)).Value
    'или автоматически вычисляем последнюю ячейку и заносим в массив данные, начиная с ячейки А3
    'llastr = Cells(Rows.Count, 1).End(xlUp).Row 'последняя ячейка столбца А
    'arr = Range(Cells(3, 1),Cells(llastr, 2)).Value
    For lr = 1 To 10000
        arr(lr,1) = lr 'заполняем массив порядковыми номерами
    Next
    'Выгружаем обработанный массив обратно на лист в те же ячейки
    Cells(1, 1).Resize(10000).Value = arr
    End Sub

    Но здесь следует учитывать и тот момент, что большие массивы могут просто вызвать переполнение памяти. Наиболее актуально это для 32-битных систем, где на VBA и Excel выделяется памяти меньше, чем в 64-битных системах

  • Если используете быстрый ЕСЛИ — IIF, то замените его на IF … Then … Else
  • Так же лучше вместо Switch() и Choose() применить тот же IF … Then … Else
  • В большинстве случаев проверять строку на «не пусто» лучше через Len(), чем прямое сравнение с пустотой: Len(s)=0 вместо s = «». Связано с тем, что работа со строками значительно медленнее, чем с числовыми данными и Len по сути не подсчитывает длину переменной, а берет это число непосредственно уже готовое из памяти. При сравнении же текста с пустой строкой(«»), VBA сначала создает в памяти переменную нулевой длинны, а уже потом сравнивает с ней наш текст. Поэтому в некоторых случаях так же ускоряет сравнение и в таком виде: s = vbNullString
  • Не применять объединение строк без необходимости. Например, s = «АВ», будет быстрее, чем: s =»А» & «В»
  • Не применять сравнение текстовых величин напрямую. Лучше применить встроенную функцию StrComp:
    If s <> s1 Then будет медленнее, чем
    If StrComp(s, s1, vbBinaryCompare) <> 0
    и тем более, если при сравнении необходимо не учитывать регистр:
    If LCase(s) <> LCase(s1) Then будет медленнее, чем
    If StrComp(s, s1, vbTextCompare) <> 0
  • Циклы For … Next в большинстве случаев работает быстрее, чем цикл Do … Lоор
  • Избегать присвоения переменным типа Variant. Хоть соблазн и велик — этот тип забирает много памяти и в дальнейшем замедляет работу кода. Так же для объектных переменных следует избегать по возможности безликого глобального типа Object и применять конкретный тип:
    Dim rRange as Object, wsSh as Object

    будет медленнее работать, чем:

    Dim rRange as Range, wsSh as Worksheet

    Причина в том, что при объявлении As Object мы не даем VBA практически никакой информации о типе данных, кроме того, что это какой-то объект. И VBA приходится «на лету» внутри кода при каждом обращении к такой переменной определять её конкретный тип(Range, Worksheet, Workbook, Chart и т.д.). Что опять же занимает время.

  • Если работаете с массивами, то можно при объявлении указать это явно:

    вместо

    Такая инициализация происходит быстрее.
    А еще лучше будет при этом еще и тип данных сразу присвоить:

    Dim arr() as string, arr2() as long

    но это только если есть уверенность в том, что в массив будут заноситься строго указанные типы данных

Конечно, это не все приемы и решения для оптимизации. Но на первых парах должно хватить. Плюс, всегда следует исходить из здравого смысла. Например, если код выполняется за 2 секунды, то вероятно нет смысла его дальше оптимизировать. Конечно, если этот код не из тех, которые просто изменяют значение одной-двух ячеек.


Статья помогла? Поделись ссылкой с друзьями!

  Плейлист   Видеоуроки


Поиск по меткам



Access
apple watch
Multex
Power Query и Power BI
VBA управление кодами
Бесплатные надстройки
Дата и время
Записки
ИП
Надстройки
Печать
Политика Конфиденциальности
Почта
Программы
Работа с приложениями
Разработка приложений
Росстат
Тренинги и вебинары
Финансовые
Форматирование
Функции Excel
акции MulTEx
ссылки
статистика

Sub Макрос1()
    Dim Rng As Range, FilteredRng As Range, LastRow As Long
 
    With Worksheets("AllData")
        If .AutoFilterMode = False Then
            .Rows(1).AutoFilter
        Else
            If .FilterMode = True Then .ShowAllData
        End If
         
        Worksheets("Sort").Cells.Clear
         
        .UsedRange.AutoFilter Field:=2, Criteria1:="=" & .Range("B1"), Operator:=xlOr, Criteria2:="=" & .Range("C1")
        With .AutoFilter.Range
            If .Resize(.Rows.Count, 1).SpecialCells(xlCellTypeVisible).Count > 1 Then
                Set FilteredRng = .Rows.SpecialCells(xlCellTypeVisible)
                FilteredRng.Copy Worksheets("Sort").Cells(1, 1)
            End If
        End With
        .ShowAllData
        .UsedRange.AutoFilter Field:=3, Criteria1:="=" & .Range("B1"), Operator:=xlOr, Criteria2:="=" & .Range("C1")
        With .AutoFilter.Range
            If .Resize(.Rows.Count, 1).SpecialCells(xlCellTypeVisible).Count > 1 Then
                Set FilteredRng = .Offset(1, 0).Resize(.Rows.Count - 1, .Columns.Count).SpecialCells(xlCellTypeVisible)
                With Worksheets("Sort")
                    LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
                    FilteredRng.Copy Worksheets("Sort").Cells(LastRow + 1, 1)
                End With
            End If
        End With
        .ShowAllData
        Range("A1").Select
    End With
       
    With Worksheets("Sort")
        'удаляем дубликаты
        .UsedRange.RemoveDuplicates Columns:=Array(1, 2, 3, 4, 5, 6, _
            7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, _
            34, 35, 36), Header:=xlYes
        
        'сортируем
        LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
        .Sort.SortFields.Clear
        .Sort.SortFields.Add Key:=Range("A2:A" & LastRow), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
        With .Sort
            .SetRange .Parent.UsedRange
            .Header = xlYes
            .MatchCase = False
            .Orientation = xlTopToBottom
            .SortMethod = xlPinYin
            .Apply
        End With
    End With
    MsgBox "Данные на лист Sort скопированы!", vbInformation, "Конец"
End Sub

Kuznetsovka

0 / 0 / 0

Регистрация: 14.04.2015

Сообщений: 6

1

14.01.2016, 18:02. Показов 3726. Ответов 7

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Есть задача, которую решил, но хотел бы ускорить работу. Проблема в том что суть программы пройти по строкам и столбцам в 1 таблице, сравнения с значениями в другой таблице, и если условие выполняется вписывать нужное значение в соответствующую ячейку, вот кусок проги:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Set Result24 = ThisWorkbook.Worksheets("24h")
Set Result5_17 = ThisWorkbook.Worksheets("6h-18h")
Set Result17_5 = ThisWorkbook.Worksheets("18h-6h")
Set Arhiv = ThisWorkbook.Worksheets("Архив")
For i = 2 To Result24.UsedRange.Rows.Count
 For j = 2 To Result24.UsedRange.Columns.Count
   For z = 2 To Arhiv.UsedRange.Rows.Count
    If Result24.Cells(i, 1).Value = Arhiv.Cells(z, 4).Value _
     And Arhiv.Cells(z, 3).Value >= CInt(Mid(Result24.Cells(1, j).Value, 1, 3)) _
     And Arhiv.Cells(z, 3).Value <= CInt(Mid(Result24.Cells(1, j).Value, 5, 7)) Then
      Result24.Cells(i, j) = 3 + Result24.Cells(i, j)
    
      If Arhiv.Cells(z, 6).Value >= 5 And Arhiv.Cells(z, 6).Value <= 17 Then
      Result5_17.Cells(i, j) = 3 + Result5_17.Cells(i, j)
      End If
      
      If Arhiv.Cells(z, 6).Value >= 17 And Arhiv.Cells(z, 6).Value <= 5 Then
      Result17_5.Cells(i, j) = 3 + Result17_5.Cells(i, j)
      End If
      
    End If
   Next z
  Next j
 Next i

Работает прога в Excelе, пробовал сделать тоже в accessе скорость не улучшилась.
Количество циклов примерно равно: 30000 * 76 * 20 = 45,6 миллионов циклов. Скорость выполнения примерно 1.5-2 часа.

Подскажите, у кого какие идеи?



0



Hugo121

6875 / 2807 / 533

Регистрация: 19.10.2012

Сообщений: 8,562

14.01.2016, 18:43

2

Лучший ответ Сообщение было отмечено Kuznetsovka как решение

Решение

1. если влезет всё в память — взять данные в массивы, перебирать их.
2. цепочку (все цепочки) AND преобразовать в лесенку IF-THEN, вглубь положить наиболее вероятное, снаружи наименее.

Добавлено через 30 минут
Ещё — вот это

Visual Basic
1
2
CInt(Mid(Result24.Cells(1, j).Value, 1, 3))
CInt(Mid(Result24.Cells(1, j).Value, 5, 7))

можно извлечь один раз перед циклом в две переменные, а не тратить время в цикле.



0



shanemac51

Модератор

Эксперт MS Access

11342 / 4661 / 748

Регистрация: 07.08.2010

Сообщений: 13,505

Записей в блоге: 4

14.01.2016, 20:54

3

а это разве возможно

Visual Basic
1
If Arhiv.Cells(z, 6).Value >= 17 And Arhiv.Cells(z, 6).Value <= 5 Then

Добавлено через 1 час 9 минут
в былые времена я бы сделала так

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Sub Test160114()
Set Result24 = ThisWorkbook.Worksheets("24h")
Set Result5_17 = ThisWorkbook.Worksheets("6h-18h")
Set Result17_5 = ThisWorkbook.Worksheets("18h-6h")
Set Arhiv = ThisWorkbook.Worksheets("Архив")
 
Dim I24K, J24K, ZAK, I, J, Z
I24K = Result24.UsedRange.Rows.Count
J24K = Result24.UsedRange.Columns.Count
ZAK = Arhiv.UsedRange.Rows.Count
Dim M24_1_3, M24_5_7
ReDim M24_1_3(0 To J24K)
ReDim M24_5_7(0 To J24K)
For J = 2 To J24K
M24_1_3(J) = CInt(Mid(Result24.Cells(1, J).Value, 1, 3))
M24_5_7(J) = CInt(Mid(Result24.Cells(1, J).Value, 5, 7))
Next J
 
For I = 2 To I24K
For J = 2 To J24K
r24 = Result24.Cells(I, J)
R17_5 = Result17_5.Cells(I, J)
R5_17 = Result5_17.Cells(I, J)
 
For Z = 2 To ZAK
z4 = Arhiv.Cells(Z, 4).Value
z3 = Arhiv.Cells(Z, 3).Value
z6 = Arhiv.Cells(Z, 6).Value
 
If Result24.Cells(I, 1).Value = z4 Then
If z3 >= M24_1_3(J) And z3 <= M24_5_7(J) Then
r24 = 3 + r24
 
If z6 > 17 Or z6 < 5 Then
R17_5 = 3 + R17_5
Else
R5_17 = 3 + R5_17
End If
 
End If
End If
Next Z
 
Result24.Cells(I, J) = r24
Result17_5.Cells(I, J) = R17_5
Result5_17.Cells(I, J) = R5_17
 
 
Next J
Next I
End Sub



1



0 / 0 / 0

Регистрация: 14.04.2015

Сообщений: 6

15.01.2016, 09:44

 [ТС]

4

Да, Вы правы, на самом деле там ИЛИ. Старый вариант кода.
If Arhiv.Cells(z, 6).Value >= 17 Or Arhiv.Cells(z, 6).Value <= 5 Then

Цитата
Сообщение от shanemac51
Посмотреть сообщение

в былые времена я бы сделала так

Спасибо за совет.
Суть уловил, но сомневаюсь, что это значительно ускорит процесс. Сегодня протестирую.



0



6875 / 2807 / 533

Регистрация: 19.10.2012

Сообщений: 8,562

15.01.2016, 09:47

5

Массивы ускорят раз так в 40.
Изменения с AND ускорят раза в 3.



0



Модератор

Эксперт MS Access

11342 / 4661 / 748

Регистрация: 07.08.2010

Сообщений: 13,505

Записей в блоге: 4

15.01.2016, 12:25

6

В массив удобно списать лист АРХИВ —в него нет обратной записи, но сложность, если позиции R24 не окажется в в АРХИВ, что даст ошибку адресации



0



0 / 0 / 0

Регистрация: 14.04.2015

Сообщений: 6

19.01.2016, 12:13

 [ТС]

7

Всем спасибо, после сегоднешнего теста вот что получилось: кол-во циклов: 50 668 800.
1. Прогнал свой вариант с разделениес If and на 2 if.
2. Прогнал предложенный вариант Sub Test160114().

Получил удивительный результат:
1. Время решения: 12:48.
2. Время решения: 24:33.

Разделение If and уменьшило время выполнения примерно в 3 раза.



0



6875 / 2807 / 533

Регистрация: 19.10.2012

Сообщений: 8,562

19.01.2016, 12:35

8

Всё логично — при AND всегда проводятся все проверки, указанные в строке, а при вложенных IF только нужные — если не прошла первая, то остальные не производятся. Если всё это ещё происходит с ячейками — разница будет заметна.



0



Цикл в цикле — ускорить работу.

ovechkin1973

Дата: Суббота, 27.01.2018, 19:33 |
Сообщение № 1

Группа: Проверенные

Ранг: Обитатель

Сообщений: 429


Репутация:

1

±

Замечаний:
0% ±


Excel 2010

накропал самостоятельно макрос с циклом (для меня это вверх моего познания VBA, поэтому сильно не смеяться)

Но срок работы его просто видимо на многие часы.. есть способ как то ускорить этот процесс?


Плохо когда не знаешь, да еще забудешь. Правильно сформулированный вопрос содержит половину ответа.

Сообщение отредактировал ovechkin1973Суббота, 27.01.2018, 19:33

 

Ответить

bmv98rus

Дата: Суббота, 27.01.2018, 20:07 |
Сообщение № 2

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

для начала избавьтесь от Sheets(«остальные сборочки»).Select и Sheets(«НКУ»).Select
Ну а следом, можно просто для перебора использовать два массива, а не переберать ячейки, и после сравнения производить.
я так понимаю Cells(i, 1).Interior.Color = 31569 — это вы просто пытались отметить, обработано или нет.


Замечательный Временно просто медведь , процентов на 20.

Сообщение отредактировал bmv98rusСуббота, 27.01.2018, 22:48

 

Ответить

ovechkin1973

Дата: Суббота, 27.01.2018, 20:14 |
Сообщение № 3

Группа: Проверенные

Ранг: Обитатель

Сообщений: 429


Репутация:

1

±

Замечаний:
0% ±


Excel 2010

я так понимаю Cells(i, 1).Interior.Color = 31569 — это вы просто пытались отметить, обраьотано или нет.

bmv98rus, Да, это цель работы макроса — сравнить и отметить.

А что значить избавиться от

Sheets(«остальные сборочки»).Select и Sheets(«НКУ»).Select

Чем то можно заменить?

Про перебор с использованием массива — это вы предложили для начальной школы.. я пока в детском саду VBA учусь..


Плохо когда не знаешь, да еще забудешь. Правильно сформулированный вопрос содержит половину ответа.

 

Ответить

ovechkin1973

Дата: Суббота, 27.01.2018, 20:15 |
Сообщение № 4

Группа: Проверенные

Ранг: Обитатель

Сообщений: 429


Репутация:

1

±

Замечаний:
0% ±


Excel 2010

и насколько или во сколько какие действия ускоряют работу?
И еще возможно глупый вопрос.. а можно как то прикинуть сколько будет работать по времени такой макрос?


Плохо когда не знаешь, да еще забудешь. Правильно сформулированный вопрос содержит половину ответа.

Сообщение отредактировал ovechkin1973Суббота, 27.01.2018, 20:24

 

Ответить

bmv98rus

Дата: Суббота, 27.01.2018, 20:58 |
Сообщение № 5

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

Ну для начала так

А прикинуть невозможно, так как зависит в том числе и от производительности ПК. То что на нем параллельно работает ….


Замечательный Временно просто медведь , процентов на 20.

Сообщение отредактировал bmv98rusСуббота, 27.01.2018, 21:00

 

Ответить

ovechkin1973

Дата: Суббота, 27.01.2018, 21:23 |
Сообщение № 6

Группа: Проверенные

Ранг: Обитатель

Сообщений: 429


Репутация:

1

±

Замечаний:
0% ±


Excel 2010

Уважаемый bmv98rus,
Пока ждал работы своего макроса (в итоге ждать не стал и остановил принудительно работу и Ваш код перезаписал) читал инфу по ускорению работы VBA.. немного стало стыдно.. Оказывается я не только про отключение обновления экрана должен знать, но и об отключении формул на время работы макроса и другие вещи, которые даже не понимая мог использовать.. Но это к лучшему.. пока Экслель «висел» я кое что прочитал.. некоторые вещи примененные Вами мне понятны. Ну и массивы Вы тоже не применяли.. так?
Макрос запустил.. буду ждать результата. Потом отпишусь. Если кто то даст ссылку с примером(и) на решение аналогичных задач с помощью массивов — будет для меня познавательно. Сам пока не смог даже приблизительно разобраться.


Плохо когда не знаешь, да еще забудешь. Правильно сформулированный вопрос содержит половину ответа.

 

Ответить

bmv98rus

Дата: Суббота, 27.01.2018, 21:41 |
Сообщение № 7

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

Ну и массивы Вы тоже не применяли.. так?

ла не применял, возможно для вашего случая такого варианта будет достаточно


Замечательный Временно просто медведь , процентов на 20.

Сообщение отредактировал bmv98rusВоскресенье, 28.01.2018, 08:58

 

Ответить

Pelena

Дата: Суббота, 27.01.2018, 21:43 |
Сообщение № 8

Группа: Админы

Ранг: Местный житель

Сообщений: 18797


Репутация:

4284

±

Замечаний:
±


Excel 2016 & Mac Excel


«Черт возьми, Холмс! Но как??!!»
Ю-money 41001765434816

 

Ответить

ovechkin1973

Дата: Суббота, 27.01.2018, 21:47 |
Сообщение № 9

Группа: Проверенные

Ранг: Обитатель

Сообщений: 429


Репутация:

1

±

Замечаний:
0% ±


Excel 2010

возможно для вашего случая такого варианта будет достаточно

Попробую после того, как первый вариант маркоса отработает. Если конечно он до утра расчет сделает. Самое противное, что мне надо часто запускать макрос, чтобы проверить работу по заполнению базы данных.. но тут уж лучше пусть комп это делает..


Плохо когда не знаешь, да еще забудешь. Правильно сформулированный вопрос содержит половину ответа.

 

Ответить

ovechkin1973

Дата: Суббота, 27.01.2018, 21:50 |
Сообщение № 10

Группа: Проверенные

Ранг: Обитатель

Сообщений: 429


Репутация:

1

±

Замечаний:
0% ±


Excel 2010

Начать можно отсюда Взять диапазон в массив
Был бы файл с примером, можно было бы говорить более предметно

Елена, завтра почитаю ссылку.. и только после этого сделаю пример для наглядности, который можно будет выложить. На дружественном форуме прочитал, как правильно задавать вопросы… понял, что делаю это как троечник :D .. поэтому вначале вашу ссылку почитаю, но это завтра..


Плохо когда не знаешь, да еще забудешь. Правильно сформулированный вопрос содержит половину ответа.

 

Ответить

bmv98rus

Дата: Суббота, 27.01.2018, 21:57 |
Сообщение № 11

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

но тут уж лучше пусть комп это делает

Вот тут возникает самый главный вопрос, может не циклом надо делать, а иными средствами . Вам что надо в итоге? У меня такое подозрение, что или формулы быстрее обработают, разве что без закраски, хотя и её условным форматом можно сделать или Power Query даст ответ. Пример из пары десятков строк двух таблиц дал бы пищку для размышлений и помощи. К стати, а почему 26000? лишнее тоже не стоит обсчитывать.


Замечательный Временно просто медведь , процентов на 20.

Сообщение отредактировал bmv98rusСуббота, 27.01.2018, 22:00

 

Ответить

ovechkin1973

Дата: Суббота, 27.01.2018, 22:13 |
Сообщение № 12

Группа: Проверенные

Ранг: Обитатель

Сообщений: 429


Репутация:

1

±

Замечаний:
0% ±


Excel 2010

ормулы быстрее обработают

bmv98rus, не знаю, возможно. Но для меня не очень удобно. Ваш макрос из поста №5 показал, что считал 23:03:15… это видимо какой то баг.. с таймером.. не считал он сутки.. около часа примерно.
Макрос из сообщения №7 ругается на [vba]

Код

arr = Sheets(«НКУ»).Range(Cells(3, 23), Cells(25788, 23))

[/vba]
Прошу прощения, но на что ругается смогу сказать только завтра.. огромное спасибо за помощь и создателям этого форума.


Плохо когда не знаешь, да еще забудешь. Правильно сформулированный вопрос содержит половину ответа.

 

Ответить

Апострофф

Дата: Суббота, 27.01.2018, 22:41 |
Сообщение № 13

Группа: Проверенные

Ранг: Обитатель

Сообщений: 416


Репутация:

117

±

Замечаний:
0% ±


Excel 1997

ругается на
[vba]

Код

arr = Sheets(«НКУ»).Range(Cells(3, 23), Cells(25788, 23))

[/vba]

Ругается он скорее всего на то, что не указан хозяин для ячеек
Cells(3, 23), Cells(25788, 23), а Sheets(«НКУ») не является активным листом.

 

Ответить

bmv98rus

Дата: Суббота, 27.01.2018, 22:46 |
Сообщение № 14

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

Апострофф, правильно заметил ,я поспешил и влепил так.


Замечательный Временно просто медведь , процентов на 20.

 

Ответить

alex77755

Дата: Воскресенье, 28.01.2018, 09:39 |
Сообщение № 15

Группа: Проверенные

Ранг: Обитатель

Сообщений: 362


Репутация:

64

±

Замечаний:
0% ±


Цитата

не считал он сутки.. около часа примерно

работы макросу на этих данных без закраски несколько секунд
1. считать одну таблицу одной строкой в массив
2. загнать массив в словарь
3. считать в массив вторую таблицу
4. пробежаться по массиву 1 раз проверяя наличие в словаре. Если есть — ставить метку в 30 колонку
5. вывалить массив на лист


Могу помочь в VB6, VBA
Alex77755@mail.ru

 

Ответить

ovechkin1973

Дата: Воскресенье, 28.01.2018, 09:40 |
Сообщение № 16

Группа: Проверенные

Ранг: Обитатель

Сообщений: 429


Репутация:

1

±

Замечаний:
0% ±


Excel 2010

Прикладываю файл для наглядности.. Применить маркрос и поста №7 так и не смог..
Елена — смотрел инфу по вашей ссылке. Разобраться не смог.. Точнее не представляю пока что с этим делать.. я про массивы. Я так понимаю у меня должно быть для ускорения выполнения моей задачи два двухмерных массива. По той ссылке, что вы дали самый первый пример помогает определиться с его размерами (моих знаний только на это пока хватило).. если я конечно правильно понял.
И еще пару багов обнаружил сделанных своими руками:
1. Я в 30 столбце хотел проставлять нумерацию найденных совпадений между листами.. т.е. если макрос нашел на обоих листах в 23 столбцах цифру 2 (Абакан), то и в 30 столбце номер должен быть одинаковый, который циклом проставляется.. У меня обои листы идентичны, я только на первом от Я до А фильтр сделал для проверки и не верно работает макрос..
2. На листе 2 (остальные сборочки) после срабатывания макроса не работам фильтр или сортировка по цвету.. на листе1 (НКУ) работает… чего я «накосячить» мог для этого? B маркос закрашивает все данные в столбце 1.. такого по задумке не должно быть.. т.е. получается на листе «остальные сборочки» он сразу красит не дожидаясь проверки?
3. Ну и это наверно не только цикл в цикле, т.е. двойной, а тройной надо делать.. Допустим из 1111 городов он находит совпадений 768 (столько закрашивается городов на листе НКУ)… Как сделать, чтобы нуменация найденных совпадений на обоих листах в столбце 30 была от 1 до 768 тогда?

К сообщению приложен файл:

3_2.xlsm
(74.6 Kb)


Плохо когда не знаешь, да еще забудешь. Правильно сформулированный вопрос содержит половину ответа.

Сообщение отредактировал ovechkin1973Воскресенье, 28.01.2018, 09:44

 

Ответить

ovechkin1973

Дата: Воскресенье, 28.01.2018, 09:42 |
Сообщение № 17

Группа: Проверенные

Ранг: Обитатель

Сообщений: 429


Репутация:

1

±

Замечаний:
0% ±


Excel 2010

alex77755, Это мой первый макрос с циклом сделанный своими ручками.. я про пост №1.. То, что вы предлагаете я пока даже и осмыслить не могу..


Плохо когда не знаешь, да еще забудешь. Правильно сформулированный вопрос содержит половину ответа.

 

Ответить

alex77755

Дата: Воскресенье, 28.01.2018, 10:41 |
Сообщение № 18

Группа: Проверенные

Ранг: Обитатель

Сообщений: 362


Репутация:

64

±

Замечаний:
0% ±


Цитата

Прикладываю файл для наглядности

С этого всегда надо начинать. Уверен, что вопрос уже давно был бы решен
посмотрю сейчас


Могу помочь в VB6, VBA
Alex77755@mail.ru

Сообщение отредактировал alex77755Воскресенье, 28.01.2018, 10:41

 

Ответить

ovechkin1973

Дата: Воскресенье, 28.01.2018, 11:40 |
Сообщение № 19

Группа: Проверенные

Ранг: Обитатель

Сообщений: 429


Репутация:

1

±

Замечаний:
0% ±


Excel 2010

С этого всегда надо начинать. Уверен, что вопрос уже давно был бы решен
посмотрю сейчас

Согласен.. вчера окрыленный тем, что хоть что то сам смог сделать элементарное пытался без примера решить проблему.. в итоге время потеряно ( не скажу, что зря).. нашел кучу ошибок..
Ошибки я устранил.. но похоже опять код по производительности ухудшил..

К сообщению приложен файл:

__3.xlsm
(86.0 Kb)


Плохо когда не знаешь, да еще забудешь. Правильно сформулированный вопрос содержит половину ответа.

 

Ответить

alex77755

Дата: Воскресенье, 28.01.2018, 11:54 |
Сообщение № 20

Группа: Проверенные

Ранг: Обитатель

Сообщений: 362


Репутация:

64

±

Замечаний:
0% ±


без заливки, но быстро. С указанием номеров строк совпадения.
Нашлось 18 значений для которых нет совпадений

К сообщению приложен файл:

3_2_.xlsm
(79.1 Kb)


Могу помочь в VB6, VBA
Alex77755@mail.ru

Сообщение отредактировал alex77755Воскресенье, 28.01.2018, 12:22

 

Ответить

Содержание

  • Настройки для ускорения кода VBA
  • Лучшие практики для повышения скорости VBA
  • Советы передовой передовой практики

В этом руководстве будет рассказано, как ускорить макросы VBA и другие передовые практики VBA.

Ниже вы найдете несколько советов по ускорению кода VBA. Подсказки слабо организованы по важности.

Самый простой способ повысить скорость вашего кода VBA — отключить ScreenUpdating и отключить автоматические вычисления. Эти настройки должны быть отключены во всех больших процедурах.

Отключить обновление экрана

По умолчанию Excel отображает изменения в книгах в реальном времени по мере выполнения кода VBA. Это приводит к значительному снижению скорости обработки, поскольку Excel чаще всего интерпретирует и отображает изменения для каждой строки кода.

Чтобы отключить обновление экрана:

1 Application.ScreenUpdating = False

В конце макроса вы должны снова включить обновление экрана:

1 Application.ScreenUpdating = True

Пока ваш код работает, вам может потребоваться «обновить» экран. Команды «обновить» нет. Вместо этого вам нужно будет снова включить обновление экрана и снова отключить его.

Установите для расчетов значение «Вручную»

При изменении значения ячейки Excel должен следовать «дереву вычислений» для пересчета всех зависимых ячеек. Кроме того, при изменении формулы Excel потребуется обновить «дерево вычислений» в дополнение к повторному вычислению всех зависимых ячеек. В зависимости от размера вашей книги эти перерасчеты могут привести к неоправданно медленной работе макросов.

Чтобы установить для расчетов ручной режим:

1 Application.Calculation = xlManual

Чтобы вручную пересчитать всю книгу:

Обратите внимание, что вы также можете рассчитать только лист, диапазон или отдельную ячейку, если это необходимо для повышения скорости.

Чтобы восстановить автоматические расчеты (в конце процедуры):

1 Application.Calculation = xlAutomatic

Важный! Это настройка Excel. Если вы не переустанавливаете вычисления на автоматический, ваша книга не будет пересчитывать, пока вы не скажете.

Вы увидите самые большие улучшения по сравнению с указанными выше настройками, но есть несколько других настроек, которые могут иметь значение:

Отключить события

События — это «триггеры», которые вызывают особые процедуры проведения мероприятий бежать. Примеры включают: когда любая ячейка на листе изменяется, когда лист активирован, когда книга открыта, перед сохранением книги и т. Д.

Отключение событий может привести к незначительному повышению скорости при запуске любых макросов, но улучшение скорости может быть намного больше, если ваша книга использует события. А в некоторых случаях отключение событий необходимо, чтобы избежать бесконечных циклов.

Чтобы отключить события:

1 Application.EnableEvents = False

Чтобы снова включить события:

1 Application.EnableEvents = True

Отключить PageBreaks

Отключение PageBreaks может помочь в определенных ситуациях:

  • Вы ранее установили свойство PageSetup для соответствующего листа а также ваша процедура VBA изменяет свойства многих строк или столбцов
  • ИЛИ Ваша процедура VBA заставляет Excel вычислять разрывы страниц (отображение предварительного просмотра или изменение любых свойств PageSetup).

Чтобы отключить PageBreaks:

1 ActiveSheet.DisplayPageBreaks = False

Чтобы снова включить PageBreaks:

1 ActiveSheet.DisplayPageBreaks = True

Лучшие практики для повышения скорости VBA

Избегайте активации и выбора

Когда вы записываете макрос, вы увидите множество методов Activate и Select:

12345678 Sub Slow_Example ()Таблицы («Лист2»). ВыберитеДиапазон («D9»). ВыберитеActiveCell.FormulaR1C1 = «пример»Диапазон («D12»). ВыбратьActiveCell.FormulaR1C1 = «демо»Диапазон («D13»). ВыбратьКонец подписки

Активация и выбор объектов обычно не нужны, они добавляют беспорядок в ваш код и отнимают очень много времени. По возможности следует избегать использования этих методов.

Улучшенный пример:

1234 Sub Fast_Example ()Листы («Sheet2»). Диапазон («D9»). FormulaR1C1 = «example»Листы («Sheet2»). Range («D12»). FormulaR1C1 = «demo»Конец подписки

Избегайте копирования и вставки

Копирование требует значительного объема памяти. К сожалению, вы не можете указать VBA очистить внутреннюю память. Вместо этого Excel будет очищать внутреннюю память через (по-видимому) определенные интервалы. Поэтому, если вы выполняете много операций копирования и вставки, вы рискуете перегрузить слишком много памяти, что может резко замедлить ваш код или даже привести к сбою Excel.

Вместо копирования и вставки рассмотрите возможность установки свойств значений ячеек.

123456789 Sub CopyPaste ()’ПомедленнееДиапазон («a1: a1000»). Копировать диапазон («b1: b1000»)’БыстрееДиапазон («b1: b1000»). Значение = Диапазон («a1: a1000»). ЗначениеКонец подписки

Используйте циклы For Each вместо циклов For

При просмотре объектов цикл For Each быстрее, чем цикл For Loop. Пример:

Это цикл для:

123456 Sub Loop1 ()dim i as RangeДля i = от 1 до 100Ячейки (i, 1). Значение = 1Далее яКонец подписки

Медленнее, чем для каждого цикла:

123456 Sub Loop2 ()Тусклая ячейка как диапазонДля каждой ячейки в диапазоне («a1: a100»)cell.Value = 1Следующая ячейкаКонец подписки

Объявление переменных / использование явного параметра

VBA не требует объявления переменных, если только вы не добавите Option Explicit в верхнюю часть модуля:

Добавление Option Explicit — это лучший способ кодирования, поскольку он снижает вероятность ошибок. Это также заставляет вас объявлять свои переменные, что немного увеличивает скорость вашего кода (преимущества тем заметнее, чем больше используется переменная).Как Option Explicit предотвращает ошибки?Самым большим преимуществом Option Explicit является то, что он помогает выявлять орфографические ошибки в именах переменных. Например, в следующем примере мы установили переменную с именем «var1», но позже мы будем ссылаться на переменную с именем «varl». Переменная «varl» не определена, поэтому она пуста, что приводит к неожиданным результатам.

1234 Sub OptionExplicit ()var1 = 10MsgBox varlКонец подписки

Использовать с — конец с утверждениями

Если вы ссылаетесь на одни и те же объекты несколько раз (например, диапазоны, рабочие листы, рабочие книги), рассмотрите возможность использования оператора With. Он быстрее обрабатывается, может упростить чтение и упростить код.С примером утверждения:

12345678 Sub Faster_Example ()С листами («Лист2»).Range («D9»). FormulaR1C1 = «example».Range («D12»). FormulaR1C1 = «demo».Range («D9»). Font.Bold = True.Range («D12»). Font.Bold = TrueКонец сКонец подписки

Быстрее, чем:

123456 Sub Slow_Example ()Листы («Sheet2»). Диапазон («D9»). FormulaR1C1 = «example»Листы («Sheet2»). Range («D12»). FormulaR1C1 = «demo»Листы («Лист2»). Диапазон («D9»). Полужирный шрифт = TrueЛисты («Лист2»). Диапазон («D12»). Полужирный шрифт = TrueКонец подписки

Советы передовой передовой практики

Защитить UserInterfaceOnly

Рекомендуется защищать листы от редактирования незащищенных ячеек, чтобы конечный пользователь (или вы!) Случайно не повредил книгу. Однако это также защитит лист (ы) от разрешения VBA вносить изменения. Таким образом, вы должны снять защиту и повторно защитить рабочие листы, что отнимает очень много времени, когда выполняется на многих листах.

12345 Sub UnProtectSheet ()Таблицы («sheet1»). Снять защиту с «пароля»’Редактировать Sheet1Таблицы («лист1»). Защитить «пароль»Конец подписки

Вместо этого вы можете защитить листы, установив UserInterfaceOnly: = True. Это позволяет VBA вносить изменения в листы, при этом защищая их от пользователя.

1 Таблицы («sheet1»). Защитить пароль: = «пароль», UserInterFaceOnly: = True

Важный! UserInterFaceOnly сбрасывается в значение False при каждом открытии книги. Итак, чтобы использовать эту замечательную функцию, вам нужно будет использовать события Workbook_Open или Auto_Open, чтобы устанавливать параметр каждый раз при открытии книги.

Поместите этот код в модуль Thisworkbook:

123456 Частная вспомогательная книга_Open ()Dim ws как рабочий листДля каждого ws в листахws.Protect Password: = «пароль», UserInterFaceOnly: = TrueСледующий wsКонец подписки

или этот код в любом штатном модуле:

123456 Частный Sub Auto_Open ()Dim ws как рабочий листДля каждого ws в листахws.Protect Password: = «пароль», UserInterFaceOnly: = TrueСледующий wsКонец подписки

Использование массивов для редактирования больших диапазонов

Обработка большого количества ячеек (например, 100 000+) может занять очень много времени. Вместо того, чтобы перебирать диапазоны ячеек, манипулируя каждой ячейкой, вы можете загрузить ячейки в массив, обработать каждый элемент в массиве, а затем вывести массив обратно в их исходные ячейки. Загрузка ячеек в массивы для манипуляций может быть намного быстрее.

1234567891011121314151617181920212223242526272829303132 Sub LoopRange ()Тусклая ячейка как диапазонDim tStart как двойнойtStart = ТаймерДля каждой ячейки в диапазоне («A1: A100000»)cell.Value = cell.Value * 100Следующая ячейкаDebug.Print (Таймер — tStart) & «секунды»Конец подпискиSub LoopArray ()Dim arr как вариантТусклый элемент как вариантDim tStart как двойнойtStart = Таймерarr = Диапазон («A1: A100000»). ЗначениеДля каждого элемента в обр.item = элемент * 100Следующий элементДиапазон («A1: A100000»). Значение = прибл.Debug.Print (Таймер — tStart) & «секунды»Конец подписки

Понравилась статья? Поделить с друзьями:
  • Как управлять программой excel
  • Как ускорить excel в windows 10
  • Как управлять листами в excel
  • Как ускорить excel 2019
  • Как управлять значениями в excel