前の会社で書いた報告書を見つけたので、サクッとネットの海へ放流。
バリバリ報告書っぽい体裁になってたので、ふんわり意訳版。
概要
- ExcelVBAのパフォーマンス調査の結果&考察。
測定準備
- 動作環境(やばい古い)
- 測定方法
- if文を用いて1つのコードにつき10 回の測定を行い、平均値も考慮して結果を比較する
- 測定を正確に行うため、以下のWindows APIを使用して時間を測定するためのクラスを用いた
- QueryPerformanceCounter:コンピュータが起動してからのクロック数を求める
- QueryPerformanceFrequency:クロックの周波数を求める
- 測定に使用したプロシージャと時間測定用クラスのソースコードは後述
- 測定内容
- 詳細は「測定結果・考察」に後述
- 基本的に、 以下サイトを参考に作成したコード、もしくは同一コードによる追試
測定結果・考察
画面の更新(画面更新の有無による処理時間の違いを調査する)
Dim i As Integer, j As Integer
Application.ScreenUpdating = True
For i = 1 To 100
For j = 1 To 10
Cells(j + 54, 17).Select
Selection.Value = j
Next j
Next i
Dim i As Integer, j As Integer
Application.ScreenUpdating = False
For i = 1 To 100
For j = 1 To 10
Cells(j + 54, 18).Select
Selection.Value = j
Next j
Next i
- 測定結果・考察
- 詳細な結果は下の表のとおり
- 画面の更新を行わない場合は、更新を行う場合の約5分の1の時間で処理
- 画面の更新を止めておくと処理速度の大幅な上昇が期待できる
試行 |
A |
B |
(B/A)*100 |
1 |
492.7216 |
97.69845 |
19.82833 |
2 |
488.2042 |
97.89708 |
20.05248 |
3 |
492.0748 |
95.996 |
19.50841 |
4 |
492.6925 |
96.52847 |
19.59203 |
5 |
489.2806 |
95.87084 |
19.59425 |
6 |
488.0673 |
96.76733 |
19.82663 |
7 |
487.2351 |
96.22284 |
19.74875 |
8 |
489.0856 |
96.83409 |
19.79901 |
9 |
491.049 |
96.30749 |
19.6126 |
10 |
487.2404 |
95.94348 |
19.6912 |
平均 |
489.7651 |
96.60661 |
19.72537 |
Selectメソッドの使用(セルの選択の有無による処理時間の違いを調査する)
Dim i As Integer, j As Integer
For i = 1 To 100
For j = 1 To 10
Cells(j + 53, 4).Select
Selection.Value = j
Next j
Next i
Dim k As Integer, l As Integer
For k = 1 To 100
For l = 1 To 10
Cells(l + 53, 5).Value = l
Next l
Next k
- 測定結果・考察
- 詳細な結果は下の表のとおり
- Selectを使用しない場合は使用する場合に比べて17%ほどの時間で処理
- ただしケースDは実行時間の誤差が大きく、期待通りの時間短縮にならないこともある
試行 |
C |
D |
(D/C)*100 |
1 |
465.02167 |
78.934334 |
16.974334 |
2 |
457.84478 |
80.925928 |
17.675407 |
3 |
459.8509 |
78.987972 |
17.176866 |
4 |
459.09326 |
80.210753 |
17.47156 |
5 |
459.11478 |
79.451159 |
17.305293 |
6 |
458.91699 |
78.998029 |
17.214013 |
7 |
460.53646 |
78.367223 |
17.016508 |
8 |
459.17652 |
79.591121 |
17.333448 |
9 |
461.22426 |
79.251134 |
17.182776 |
10 |
458.37055 |
79.163693 |
17.270676 |
平均 |
459.91502 |
79.388135 |
17.262088 |
Value プロパティの記述(Value プロパティを省略する場合と記述する場合の処理時間の違いを調査する)
Dim i As Long
For i = 1 To 10000
Range("F54") = i
Next i
Dim i As Long
For i = 1 To 10000
Range("F54").Value = i
Next i
- 測定結果・考察
- 詳細な結果は下の表のとおり
- 処理時間はほぼ同じで、Value プロパティの省略は実行時間に影響を与えないと考えてよい
試行 |
E |
F |
(F/E)*100 |
1 |
2326.4577 |
2345.0455 |
100.79898 |
2 |
2324.4613 |
2337.1275 |
100.54491 |
3 |
2329.7536 |
2335.5049 |
100.24686 |
4 |
2347.5447 |
2331.6855 |
99.324431 |
5 |
2339.4532 |
2349.2494 |
100.41874 |
6 |
2326.0666 |
2335.1348 |
100.38985 |
7 |
2323.0444 |
2329.5581 |
100.28039 |
8 |
2345.9035 |
2330.3953 |
99.338928 |
9 |
2329.1851 |
2362.5732 |
101.43346 |
10 |
2330.7468 |
2335.5527 |
100.2062 |
平均 |
2332.2617 |
2339.1827 |
100.29827 |
セルの指定方法(セルの指定方法による処理時間の違いを調査する)
Dim i As Long
For i = 1 To 10000
Range("F56") = Rnd
Next i
Dim i As Long
For i = 1 To 10000
Cells(56, 6) = Rnd
Next i
- 測定結果・考察
- 詳細な結果は下の表のとおり
- RangeプロパティよりもCellsプロパティを使用した場合の方が早く処理を終えている
試行 |
G |
H |
(H/G)*100 |
1 |
2421.3896 |
2277.0321 |
94.038239 |
2 |
2389.8699 |
2291.2066 |
95.871601 |
3 |
2387.951 |
2282.2504 |
95.573586 |
4 |
2404.8618 |
2299.6845 |
95.626471 |
5 |
2381.5926 |
2285.0334 |
95.945604 |
6 |
2388.6293 |
2277.1433 |
95.332639 |
7 |
2388.7131 |
2277.4294 |
95.34127 |
8 |
2397.8883 |
2279.875 |
95.078448 |
9 |
2382.8615 |
2295.9938 |
96.354478 |
10 |
2383.6088 |
2285.588 |
95.887713 |
平均 |
2392.7366 |
2285.1236 |
95.505005 |
セルの参照に配列を使用する(配列に移したデータを参照するか、セルを直接参照するかの違いを調査する)
Dim i As Long, j As Long, buf As Long
For i = 1 To 10000
For j = 1 To 100
buf = Cells(i + 80, j + 2)
Next j
Next i
Dim i As Long, j As Long, buf As Long, C As Variant
C = Range("C81:CX10080")
For i = 1 To 10000
For j = 1 To 100
buf = C(i, j)
Next j
Next i
- 測定結果・考察
- 詳細な結果は下の表のとおり
- セルを配列に格納してからデータを参照した方が、約7%という短時間で処理を終えている
- 多くのデータを扱う場合は特に、配列に格納し使用すると、処理速度の大幅な上昇が期待できる
試行 |
I |
J |
(J/I)*100 |
1 |
9563.1584 |
645.33789 |
6.7481668 |
2 |
9568.8748 |
661.04072 |
6.9082388 |
3 |
9557.432 |
659.11617 |
6.8963731 |
4 |
9566.9553 |
660.18083 |
6.9006367 |
5 |
9555.9391 |
658.64293 |
6.8924982 |
6 |
9569.343 |
659.31145 |
6.8898298 |
7 |
9562.0421 |
661.05944 |
6.9133709 |
8 |
9554.2299 |
658.96671 |
6.8971201 |
9 |
9553.607 |
663.79163 |
6.9480734 |
10 |
9585.2875 |
668.88389 |
6.9782351 |
平均 |
9563.6869 |
659.63317 |
6.8972543 |
メインプロシージャ
Public Sub SpeedComp ()
Dim cnt As Long
Dim myQPT As New QueryPerformanceTimer
For cnt = 1 To 10
Call myQPT.BeginTimer
Cells(cnt, 1).Value = myQPT.EndTimer
Next
End Sub
測定用クラス
Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Boolean
Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Boolean
Private m_curFreq As Currency
Private m_curStartTime As Currency
Public Function BeginTimer() As Boolean
If m_curFreq = 0 Then
If QueryPerformanceFrequency(m_curFreq) = False Then
BeginTimer = False
End If
End If
Call QueryPerformanceCounter(m_curStartTime)
BeginTimer = True
End Function
Public Function EndTimer() As Double
Dim curEndTime As Currency
If m_curFreq <> 0 Then
Call QueryPerformanceCounter(curEndTime)
EndTimer = ((curEndTime - m_curStartTime) / m_curFreq) * 1000
Else
EndTimer = -1
End If
End Function
Private Sub Class_Initialize()
m_curFreq = 0
m_curStartTime = 0
End Sub
参考文献
- Microsoft サポートオンライン(QueryPerformanceCounter について)
- Office TANAKA
- MSDN(ScreenUpdating プロパティ、Select メソッド、Value プロパティについて)