機能と数式 | VBA | セミナー | オンラインソフト | お問い合わせ | その他
Top > Excel > VBA > VBA高速化テクニック

名前で呼ぶな!



学校の学級を思い浮かべてください。生徒の一人に、出席番号15番の田中クンがいたとき、先生が田中クンを指名するには2通りの呼び方があります。

(1)「田中クン!」
(2)「出席番号15番の者!」

どちらも同一人物を指していますが、(1)の呼び方は生徒オブジェクトの名前を直接指定しているのに対し、(2)では生徒コレクション内のインデックス値を指定しています。
学校の学級でしたらどちらも同じ結果でしょうけど、VBAではこうした呼び方の違いによっても速度が変わってきます。

 Test1Test2%
1回目00:1500:1280.0%
2回目00:1500:1280.0%
3回目00:1600:1275.0%
4回目00:1500:1280.0%
5回目00:1500:1386.7%
6回目00:1500:1280.0%
7回目00:1500:1386.7%
8回目00:1500:1280.0%
9回目00:1500:1386.7%
10回目00:1600:1381.3%
平均00:1500:1281.6%
操作のためにオブジェクトを特定するとき、そのオブジェクトがコレクションの要素の場合には、オブジェクトの名前を直接指定するのと、コレクションのインデックス値を指定する方法があります。たとえば、下のTest1はワークシートを特定するのに「Worksheets("Sheet1")」と名前で指定しています。それに対してTest2では「Worksheets(1)」とインデックス値を使っています。どちらも同じように感じますが、実は左のように、インデックス値で特定した方が若干高速になるのです。

Sub Test1()
    Dim i As Long, tmp As String
    For i = 1 To 1000000
        tmp = Worksheets("Sheet1").Name
    Next i
End Sub

Sub Test2()
    Dim i As Long, tmp As String
    For i = 1 To 1000000
        tmp = Worksheets(1).Name
    Next i
End Sub

VBAは内部で、オブジェクトをインデックス値で管理しています。そこへ「○○という名前のオブジェクト」と指定すると、内部で名前からインデックス値への変換が行われます。この変換作業にはほとんど時間を要しませんが、それでも若干の差が生じます。

それなら、全てインデックス値で指定しよう……と決めつけるのは早計です。インデックス値で指定するということは、そのオブジェクトがその位置に格納されているということが前提になるのです。たとえばワークシートの場合、Sheet1が左端に位置するときに限ってWorksheets(1)でSheet1を特定できます。次のコードをご覧ください。Sheet1を削除してから新しいシートを挿入し、Sheet1に名前を変更するマクロです。

Sub Sample()
    Application.DisplayAlerts = False
    Worksheets(1).Delete
    With Worksheets.Add
        .Name = "Sheet1"
    End With
End Sub

Sheet1が左端に位置しているとき、このマクロは正常に機能します。しかしSheet1が別な位置にあるとエラーです。そのとき下のようなエラーメッセージが表示されます。



上のメッセージを一目見て、

名前を変更できない→すでにSheet1が存在している→削除に失敗した→Sheet1の位置が左端ではない

と瞬時に判断できるマクロの上級者は、最初からこんなコードを書きません。ついこうした不安定なコードを書いてしまうビギナーは、このエラーメッセージから原因を突き止めるのに時間がかかります。マクロの上級者を目指すのなら、マクロの高速化だけでなく安定性やメンテナンス性などにも気を配りましょう。



このエントリーをはてなブックマークに追加