CurrentRegion.SpecialCells(xlCellTypeVisible) слишком медленный — советы по повышению производительности?

Я пытаюсь автоматизировать отчет, который имеет 5 разных источников информации. Я пытаюсь сделать UNION разных таблиц в одну, используя ListObjects, все работает нормально, за исключением случаев, когда я копирую первый столбец первого ListObject. Копирование первого столбца занимает около 2 минут, следующие столбцы — менее 1 секунды.

Каждый раз, когда я запускаю сценарий VBA, я удаляю все строки целевой таблицы, чтобы запустить сценарий VBA с ListObject с 0 строками.

Попробую объяснить, как это работает:

Sub ProcesarPresupuesto() 
'This is the first macro that process and copy the information of the first source

 Application.ScreenUpdating = False
 Application.DisplayAlerts = False
 Application.Calculation = xlCalculationManual

'<Here> I add several columns and process the information of this first source, I keep all the rows as values using the Function: AddColumnFormula (at the end of this example). I think this is not causing the problem.

'Then I fill all the Blanks Cells to avoid having empty cells in my final table.
Sheets("Origin").Select
Selection.CurrentRegion.Select
On Error Resume Next
Selection.SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "Null"
On Error GoTo 0

'When I have the ListObject ready I start copying the columns to the destination

Sheets("Destination").Select
Range("A1").Select
While ActiveCell.Value <> ""
Call CopyColumn("Origin", ActiveCell.Value, "Destination")
ActiveCell.Offset(0, 1).Select
Wend

End Sub

Я думаю, это должно быть очень быстро. Если я удаляю только значения Destination ListObject и оставляю строки пустыми, первый столбец копируется немедленно, поэтому я думаю, что проблема связана с тем, как Excel вычисляет первые строки, добавляемые в ListObject. Есть ли лучший способ скопировать столбец, когда таблица пуста? Я делаю что-то действительно неправильно?

Это функция CopyColumn

Function CopyColumn(Origin, ColumnName, Destination)
    Range(Origin & "[[" & ColumnName & "]]").Copy Destination:=Range(Destination & "[[" & ColumnName & "]]")
End Function

Это функция, которую я использую для обработки столбцов

Function AddColumnFormula(DestinationSheet, TableName, ColumnName, Value)

Set NewColumn = Sheets(DestinationSheet).ListObjects(TableName).ListColumns.Add
NewColumn.Name = ColumnName

Set Rango = Range(TableName & "[[" & ColumnName & "]]")
Rango.Value = Value
Rango.Copy
Rango.PasteSpecial (xlPasteValues)

End Function

Заранее спасибо за ваше время и ответы


person miguelvalenciav    schedule 30.04.2014    source источник
comment
Каков адрес этого диапазона? Range(Origin & "[[" & ColumnName & "]]")? Добавьте MsgBox Range(Origin & "[[" & ColumnName & "]]").Address и посмотрим, что он покажет.   -  person David Zemens    schedule 30.04.2014
comment
Спасибо @DavidZemens за вашу помощь, он дает мне диапазон ($ A $ 2: $ A $ 42174), который является диапазоном первого столбца в источнике. Кажется, все в порядке.   -  person miguelvalenciav    schedule 01.05.2014
comment
Хммм. Я запускаю ваш код на 45 000 строк данных, копирование 7 столбцов занимает менее секунды (с screenupdating = False) и менее 2 секунд с screenupdating = True...   -  person David Zemens    schedule 01.05.2014
comment
Привет @DavidZemens Я пытался на выходных поработать над этим, и мне не повезло. Вот пример моего файла. Я удалил некоторые рабочие листы, которые не используются для этого макроса. Странно то, что когда я тестирую его на другом компьютере, он работает лучше, но все еще медленно. Макрос называется: ProcesarPresupuesto, и он находится в ссылке модуля GenerarReporte.   -  person miguelvalenciav    schedule 06.05.2014
comment
Я запускал его один раз, он был немного медленным, но я не засекал время. Затем я внес некоторые изменения в ProcessarPresupuesto, это заняло 1m16s. Я попробовал еще несколько вещей с переменным успехом, последнее заняло 3 минуты 13 секунд, но большинство выполнений длится ~ 2 минуты каждое. В этой попытке я вставил несколько операторов Debug.Print и думаю, что проблема связана с ...CurrentRegion.SpecialCells(xlCellTypeBlanks) -- для оценки этого оператора потребовалось 2 мин 53 с. Я посмотрю на это немного дольше, но я думаю, что это виновник: и CurrentRegion, и SpecialCells являются дорогостоящими операциями. Там может быть лучший способ сделать это.   -  person David Zemens    schedule 06.05.2014


Ответы (1)


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

Я попробовал еще несколько вещей с переменным успехом, используя операторы Debug.Print, чтобы сообщить мне, какая часть кода выполняется и сколько времени они занимают. Большинство казней длились около 2 минут каждая, самая медленная — 3 минуты 13 секунд.

В последней попытке за 3 минуты 13 секунд я сосредоточился на следующем:

...CurrentRegion.SpecialCells(xlCellTypeBlanks)

Это подозрительно, потому что методы CurrentRegion и SpecialCells могут быть дорогими. Объединение их казалось рецептом катастрофы.

Я решил попробовать простую итерацию, просто чтобы сравнить производительность, и, к моему удивлению, я могу выполнить простой цикл For each для 42 000 строк и 32 столбцов данных, и это будет последовательно выполняться примерно за 14 секунд для общего запуска. -время около 30 секунд.

Вот код, который я использую для цикла:

Dim cl As Range
'Debug.Print "For each ..." & Format(Now(), "hh:mm:ss")
For Each cl In wsP.ListObjects(1).DataBodyRange
    If cl.Value = vbNullString Then cl.Value = "Null"
Next
'Debug.Print "End loop " & Format(Now(), "hh:mm:ss")

Вот мои последние три результата:

31 seconds:    
    Commencar a 21:09:25
    For each ...21:09:38
    End loop 21:09:52
    CopiarColumnaListOBjectaVacia...21:09:52
    Finito : 5/5/2014 9:09:56 PM

30 seconds:    
    Commencar a 21:10:23
    For each ...21:10:36
    End loop 21:10:49
    CopiarColumnaListOBjectaVacia...21:10:49
    Finito : 5/5/2014 9:10:53 PM

34 seconds:    
    Commencar a 21:18:42
    For each ...21:18:55
    End loop 21:19:09
    CopiarColumna... 21:19:09
    Finito : 5/5/2014 9:19:16 PM

Я сохранил исправленную версию XLSB в Документах Google, чтобы вы могли ознакомиться с ней полностью.

https://drive.google.com/file/d/0B1v0s8ldwHRYZWhuTmRuaDJoMzQ/edit?usp=sharing

Как я уже сказал, я внес некоторые изменения в эту подпрограмму, а также в RenombraColumna, но, оглядываясь назад, хотя они и могут обеспечить некоторую эффективность, я думаю, что корень проблемы был в CurrentRegion.SpecialCells.

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

person David Zemens    schedule 06.05.2014