5

我在使用列表对象(又名 Excel 表)的 excel 应用程序上遇到性能问题。我怀疑这可能是一个错误,但尽管我用谷歌搜索我找不到它的任何参考。我已经为我的应用程序开发了一个解决方法,但我感兴趣的是是否有人可以深入了解为什么会发生这种情况。

注意:我在 Windows Vista 上使用 Excel 2007。设置如下:我有一个将数据保存在列表对象中的电子表格,其中包含可以通过命令按钮启动的 VBA 代码;此代码可以对工作表上的任意数量的单元格进行多次编辑,因此 Excel 的计算模式在任何编辑之前设置为手动。

我遇到的问题是,如果当前活动的单元格在列表对象中,那么将计算模式设置为手动似乎没有任何效果。因此,如果用户碰巧在同一个实例中打开了一个繁重的计算工作簿,那么 VBA 代码会运行得很慢。实际上,我不得不将我的应用程序拆开才能发现这是由活动单元格引起的;我用这个场景的简单版本创建了一个新工作簿,以确认我的应用程序没有某种损坏。

我一直在用这个做一些测试用例,下面是我发现的结果:

  1. 虽然看起来大体上和计算有关,但是计算模式在手动和自动之间切换还是有时间差的……

    • 手动 = 7.64 秒
    • 自动 = 9.39 秒

    手动模式比自动模式快不到 20%。但我的期望是它们或多或少是相同的,考虑到问题似乎是即使在手动模式下也开始计算。

  2. 将其与活动单元格不在列表对象上时进行比较,结果大不相同......

    • 手动 = 0.14 秒
    • 自动 = 3.23 秒

    现在,手动运行快了 50 倍,而自动运行显示计算时间不应该超过 3.2 秒!所以现在第一个测试看起来可能在手动模式下运行了两次计算,在自动模式下运行了近 3 次。

  3. 再次重复这个测试,这次是在任何单元格中都没有计算公式的情况下,突然它似乎没有那么糟糕了,

    • 活动单元格是列表对象,计算是手动 = 0.17 秒
    • 活动单元格是列表对象,计算是自动的 = 0.20 秒
    • 活动单元格为空,计算为手动 = 0.14 秒
    • 活动单元格为空且计算为自动 = 0.18 秒

    它仍然较慢,但现在只有 10-20%,使其不明显。但这确实表明该问题必须以某种方式与计算有关,否则它应该花费与第一次测试一样长的时间。

如果有人想创建这些测试以自己查看,设置如下:

  • 添加了列表对象的新工作簿(不必链接到任何数据)
  • 添加一些需要 excel 一段时间才能计算的公式(我只是重复了 '=1*1' 30,000 次)
  • 编写一个快速的 VBA 代码;(i) 循环通过一个简单的单元格编辑数百次,(ii) 并记录所花费的时间
  • 然后在更改列表对象和空单元格之间的活动单元格时运行代码

我很想知道是否有人可以解释为什么 Excel 会以这种方式运行,是否是一个错误,或者是否与列表对象有关的某些功能实际上有一些真正的用途?

谢谢,斯图尔特

4

2 回答 2

2

这与您发现的“错误”无关,这非常有趣和耐人寻味。

我只是想分享一个避免计算延迟的好方法。我用这个得到了很好的结果,现在我一直在使用它。

简单地说,Excel 在“VBA 世界”和“电子表格世界”之间来回复制数据需要很长时间。

如果您一次执行所有“读取”、处理,然后一次执行所有“写入”,您将获得惊人的性能。这是使用此处记录的变体数组完成的:

http://msdn.microsoft.com/en-us/library/ff726673.aspx#xlFasterVBA

在标记为:在单个操作中读取和写入大块数据的部分中

我能够重构一些需要 5 分钟才能运行的代码,并将其缩短到 1.5 分钟。重构花了我 10 分钟,这太棒了,因为它是相当复杂的代码。

于 2012-02-04T18:27:09.153 回答
1

关于表性能(和一般性能):

我知道这是一个老问题,但我想把它记录下来。

旧版本的 Excel 和 2007 年后版本之间发生的变化是,Excel 现在激活任何 PasteSpecial 操作的目标工作表。您不能通过关闭 ScreenUpdating 并手动进行计算来覆盖它。这样的激活将使工作表可见,并导致无法控制的闪烁。

我的原始 VBA 代码在运行 Excel 2000 的旧的单处理器 XP 机器上运行得非常快。在现代机器上对 Excel 2013 的更改在代码执行的可怕缓慢中令人震惊。影响性能的三个方面是从一张纸到另一张纸的 PasteSpecial、任何其他需要激活图纸(缩放级别、高级过滤器、图纸级范围名称等)的代码,以及自动化图纸保护/取消保护。

这太糟糕了,因为 PasteSpecial 帮助“清理”了您复制的数据(直接使用 .Copy 到目标会引发偶尔的错误)。

因此,您需要检查您的代码,并确保您使用直接分配给所需数据类型的正确属性(例如,从 Value、Value2、Text 和 Formula 中),而不是 PasteSpecial。

例如 .Range("MYRANGE").Value = .Cells(5, 7).Value2

您还需要谨慎地抵制在整个代码中使用 Select 和 Activate。

如上所述,您会在 Excel 论坛中找到许多关于最后一点的评论,表明您“从不”需要使用激活,这显然是不正确的,因为 Excel 中的一些内容仅适用于或需要活动工作表。了解通过特定方法或使用对象自动强制激活的情况也将有助于编码。不幸的是,您不会在文档中看到太多。

更新:

关于条件格式,当遇到大量条件格式的单元格时,您会在各种论坛中发现许多关于 Excel 运行缓慢的抱怨。我怀疑这会影响 Excel 表格,因为它们有许多表格格式选项。为了测试这一点,我拿了一个我们使用的大型工作簿,目前它被格式化为几个工作表,上面有相同样式的 Excel 表格。

将表格转换为常规范围后,我注意到代码执行速度没有差异。这似乎表明使用 Excel 表格格式远远优于有条件地格式化您自己的单元格数组。

于 2014-10-07T00:12:48.983 回答