Excel Interop – 效率和性能

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

这里有一些我发现自己:

  • ExcelApp.ScreenUpdating = false – closures重ExcelApp.ScreenUpdating = false的屏幕

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

  • 减less对Worksheet.Cells.Item(row, col)Worksheet.Range调用 – 我必须轮询数百个单元格才能find我需要的单元格。 实现一些细胞位置的caching,将执行时间从约40秒减less到约5秒。

什么样的interop调用会对性能产生重大影响,应该避免? 你还能做什么来避免不必要的处理?

当使用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; 

请注意,它是重要的,你知道什么数据typesExcel存储(文本或数字),因为它不会自动为您做这个时,你是从对象数组转换types。 如果您不能事先确定数据types,则在必要时添加testing来validation数据。

这是谁想知道什么是最好的方式是从数据库结果集中填充Excel表。 这并不意味着是一个完整的清单,但它列出了几个选项。

一些性能数字,而试图在旧的奔腾4 3GHz框包括155列和4200logging,包括数据检索时间从不超过10秒,从最慢到最快的顺序填充Excel表格,如下所示…

  1. 一次只有一个细胞 – 只有不到11分钟

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

  3. 每次一列 – 4分钟

  4. 在SQL 2005中使用不推荐的sp_makewebtask过程来创build一个HTML文件 – 9秒+随后在Excel中加载html文件并保存为XLS / XLSX – 大约2分钟。

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

我结束了使用选项5.希望这有助于。

尽可能使用excel内置函数,例如:不要在给定的string中search整个列,而是使用Ctrl-F在GUI中提供的find命令:

 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 

如果你想sorting一些列表,请使用excel sort命令,不要在VBA中手动执行:

 Selection.Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlGuess, _ OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _ DataOption1:=xlSortNormal 

如果您正在轮询许多单元格的值,则可以一次性获取存储在variables数组中的所有单元格值:

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

根据您获得价值的范围的大小,这里有一个权衡。 我猜如果你需要一个或更多的单元格值,这可能比循环遍历不同的单元格和轮询值更快。

性能也取决于你如何自动化Excel。 VBA比COM自动化要快于.NET自动化。 通常,早期(编译时)绑定比后期绑定更快。

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

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

正如Anonymous Type所说:读取/写入大范围块对性能非常重要。

在COM-Interop开销仍然过大的情况下,您可能需要切换到使用最快的Excel界面XLL界面。

尽pipeXLL接口主要面向C ++用户,但XL DNA和Addin Express都提供.NET到XLL桥接function,这比COM-Interop快得多。

在VBA中可以做的另一件大事是使用Option Explicit并尽可能避免变体。 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 

虽然他们似乎没有像前两个那么大的差别。

与将Range值设置为数组类似,如果您正在处理的数据大多数是在列的每一行中具有相同公式的数据,那么可以对公式使用R1C1公式表示法,并将整列设置为与公式string相同以设置整个事情在一个电话。

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

另外,使用ExcelDNA和.NET创buildXLL加载项(或C中的硬性方法)也是获得UDF在多个线程上运行的唯一方法。 (请参阅Excel DNA的ExcelFunction属性的IsThreadSafe属性。

在我彻底转换到Excel DNA之前,我还尝试在.NET中创buildCOM可见库,以便在VBA项目中引用。 重文本处理比VBA快一点,就像使用包装的.NET List类而不是VBA的Collection一样,但Excel DNA更好。