Excel List-Object VBA性能错误?

时间:2012-01-14 20:56:01

标签: performance excel vba listobject

我在使用列表对象(AKA 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. 再次重复此测试,这次是在任何单元格中没有计算公式的情况下,突然间它看起来不那么糟糕,

    • 活动单元格是List Object& Calc是手动= 0.17秒
    • 活动单元格是List Object& Calc是自动= 0.20秒
    • 活动细胞是空的& Calc是手动= 0.14秒
    • 活动细胞是空的& Calc是自动= 0.18秒

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

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

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

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

    谢谢, 斯图尔特

2 个答案:

答案 0 :(得分:2)

这与您找到的“bug”无关,这非常有趣且有趣。

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

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

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

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

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

我能够重构一些我用了5分钟运行的代码并将其降低到1.5分钟。重构花了我10分钟,这是惊人的,因为它是相当复杂的代码。

答案 1 :(得分:0)

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

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

旧版本的Excel和2007年后版本之间发生了一件事,即Excel现在会激活任何PasteSpecial操作的目标工作表。您无法通过关闭ScreenUpdating并制作计算手册来覆盖它。这种激活会使纸张可见,并导致无法控制的闪烁。

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

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

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

e.g。 .Range(“MYRANGE”)。值=。细胞(5,7).Value2

您还需要严格禁止在整个代码中使用“选择”和“激活”。

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

更新

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

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