63

我想知道我能做些什么来提高 Excel 自动化的性能,因为如果你在工作表中有很多事情,它可能会很慢......

以下是我自己发现的一些:

  • ExcelApp.ScreenUpdating = false-- 关闭屏幕重绘

  • ExcelApp.Calculation = Excel.XlCalculation.xlCalculationManual-- 关闭计算引擎,以便 Excel 在单元格值更改时不会自动重新计算(完成后重新打开)

  • 减少调用,Worksheet.Cells.Item(row, col)并且Worksheet.Range——我不得不轮询数百个单元来找到我需要的单元。实施一些单元位置缓存,将执行时间从约 40 秒减少到约 5 秒。

什么样的互操作调用会严重影响性能并且应该避免?您还能做些什么来避免进行不必要的处理?

4

7 回答 7

49

使用 C# 或 VB.Net 获取或设置范围时,请计算范围的总大小,然后获取一个大型二维对象数组...

//get values
object[,] objectArray = shtName.get_Range("A1:Z100").Value2;
iFace = Convert.ToInt32(objectArray[1,1]);

//set values
object[,] objectArray = new object[3,1] {{"A"}{"B"}{"C"}};
rngName.Value2 = objectArray;

请注意,了解 Excel 存储的数据类型(文本或数字)很重要,因为当您将类型从对象数组转换回时,它不会自动为您执行此操作。如果您无法事先确定数据类型,则在必要时添加测试以验证数据。

于 2010-02-19T04:34:06.993 回答
13

这适用于任何想知道从数据库结果集中填充 excel 工作表的最佳方法的人。这绝不是一个完整的列表,但它确实列出了一些选项。

尝试在旧的 Pentium 4 3GHz 机器上填充具有 155 列和 4200 条记录的 Excel 工作表时的一些性能数据,包括从最慢到最快的顺序从不超过 10 秒的数据检索时间如下...

  1. 一次一个单元格 -不到 11 分钟

  2. 通过转换为 html 来填充数据集 + 将 html 保存到磁盘 + 将 html 加载到 excel 中并将工作表保存为 xls/xlsx - 5 分钟

  3. 一次一列 - 4 分钟

  4. 使用 SQL 2005 中已弃用的 sp_makewebtask 过程创建 HTML 文件 - 9 秒 + 然后在 excel 中加载 html 文件并保存为 XLS/XLSX -大约 2 分钟。

  5. 将 .Net 数据集转换为 ADO RecordSet 并使用 WorkSheet.Range[].CopyFromRecordset 函数填充 excel - 45 秒!

我最终使用了选项 5。希望这会有所帮助。

于 2011-10-06T15:37:59.587 回答
6

If you're polling values of many cells you can get all the cell values in a range stored in a variant array in one fell swoop:

Dim CellVals() as Variant
CellVals = Range("A1:B1000").Value

There is a tradeoff here, in terms of the size of the range you're getting values for. I'd guess if you need a thousand or more cell values this is probably faster than just looping through different cells and polling the values.

于 2008-12-15T18:31:10.523 回答
5

尽可能使用 excels 内置功能,例如:不要在整个列中搜索给定的字符串,而是使用findGUI 中通过 Ctrl-F 提供的命令:

Set Found = Cells.Find(What:=SearchString, LookIn:=xlValues, _
    SearchOrder:=xlByRows, SearchDirection:=xlNext, _
    MatchCase:=False, SearchFormat:=False)

If Not Found Is Nothing Then
    Found.Activate
    (...)
EndIf

如果要对某些列表进行排序,请使用 excelsort命令,不要在 VBA 中手动进行:

Selection.Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlGuess, _
    OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
    DataOption1:=xlSortNormal
于 2008-12-10T15:12:32.077 回答
2

正如匿名类型所说:读/写大范围块对性能非常重要。

如果 COM-Interop 开销仍然太大,您可能希望切换到使用 XLL 接口,这是最快的 Excel 接口。

尽管 XLL 接口主要是为 C++ 用户设计的,但 XL DNA 和 Addin Express 都提供了 .NET 到 XLL 的桥接功能,这比 COM-Interop 快得多。

于 2015-02-08T12:40:29.583 回答
2

性能还很大程度上取决于您如何自动化 Excel。VBA 比 COM 自动化快,比 .NET 自动化快。而且通常早期(编译时)绑定也比后期绑定更快。

如果您遇到严重的性能问题,您可以考虑将代码的关键部分移至 VBA 模块并从您的 COM/.NET 自动化代码中调用该代码。

如果您使用 .NET,您还应该使用 Microsoft 提供的优化的主互操作程序集,而不是使用自定义构建的互操作程序集。

于 2008-12-10T15:11:19.083 回答
0

您可以在 VBA 中做的另一件大事是使用 Option Explicit 并尽可能避免 Variants。在 VBA 中,变体不是 100% 可以避免的,但它们会使解释器在运行时做更多的工作并浪费内存。

当我开始在 Excel 中使用 VBA 时,我发现这篇文章非常有帮助。
http://www.ozgrid.com/VBA/SpeedingUpVBACode.htm

还有这本书

http://www.amazon.com/VB-VBA-Nutshell-Language-OReilly/dp/1565923588

如同

 app.ScreenUpdates = false //and
 app.Calculation = xlCalculationManual

你也可以设置

 app.EnableEvents = false //Prevent Excel events
 app.Interactive = false  //Prevent user clicks and keystrokes

尽管它们似乎没有前两个那么大。

与将范围值设置为数组类似,如果您正在处理的数据主要是在列的每一行中具有相同公式的表格,您可以为您的公式使用 R1C1 公式表示法并将整个列设置为等于要设置的公式字符串一次通话即可完成所有工作。

app.ReferenceStyle = xlR1C1
app.ActiveSheet.Columns(2) = "=SUBSTITUTE(C[-1],"foo","bar")"

此外,使用 ExcelDNA 和 .NET(或 C 中的硬方法)创建 XLL 插件也是使 UDF 在多个线程上运行的唯一方法。(请参阅 Excel DNA 的 ExcelFunction 属性的 IsThreadSafe 属性。)

在完全过渡到 Excel DNA 之前,我还尝试在 .NET 中创建 COM 可见库以在 VBA 项目中引用。这样,繁重的文本处理比 VBA 快一点,使用包装的 .NET List 类而不是 VBA 的 Collection,但 Excel DNA 更好。

于 2015-07-16T23:36:37.590 回答