#32 $付き関数のメリットとは?

結論
$なしの関数に比べて、$付きの関数を使った方が高速である。ただし、同じ$付き関数を使った場合でも、代入先が文字列型でない場合には、データ型変換の分、処理時間がかかるので、$付き関数を使った場合の返り値の代入先は、文字列型変数とすべきである。また、$なし関数を使う場合は処理時間がかかるが、その返り値をバリアント型に代入するとさらに時間がかかる。

VBAにはたくさんの関数がありますが、どんな関数があってどんなことができるかを知っておくことは、プログラミングする上で非常に重要です。まとまった処理を簡単にしてくれる関数を知らなかったばかりに、独自の長いコードを書いてしまったということもあるでしょう。それは独自の関数を作るための労力だけでなく、実際に動かした際のパフォーマンス面でもムダを発生させることになってしまいます。

しかし、関数の名前や用途を知っていても、さらに注意しなければならないことは色々あります。その1つが$付きと$なしの同じ名前の関数の存在です。Mid$関数とMid関数、Left$関数とLeft関数など、文字列処理を行う関数に多く存在しています。基本的な違いとして、$が付いた関数は文字列型の値を返します。一方付いていないものはバリアント型の値を返します。一般に、バリアント型の関数や変数は処理が遅いといわれていますので、単純に名前が似ているからといって、混同して使うのはよくないはずです。ここでは、それらの処理時間を比較することによって、それを確認してみたいと思います。


ここでは、テスト用のサンプルコードとして次のようなものを用意してみました。


Dim strData As String
Dim strDummy As String
Dim varDummy As Variant
Dim ilnglLoop As Long

'テスト用の文字列を生成
strData = ""
For ilnglLoop = 1 To 100
  strData = strData & "A"
Next ilnglLoop

ts_Watch "処理開始", True


'Mid$とMidの比較
For ilnglLoop = 1 To 1000000
  strDummy = Mid$(strData, 50, 10)
Next ilnglLoop
ts_Watch "Mid$で文字列型変数へ格納"

For ilnglLoop = 1 To 1000000
  varDummy = Mid$(strData, 50, 10)
Next ilnglLoop
ts_Watch "Mid$でバリアント型変数へ格納"

For ilnglLoop = 1 To 1000000
  strDummy = Mid(strData, 50, 10)
Next ilnglLoop
ts_Watch "Midで文字列型変数へ格納"

For ilnglLoop = 1 To 1000000
  varDummy = Mid(strData, 50, 10)
Next ilnglLoop
ts_Watch "Midでバリアント型変数へ格納"


'Left$とLeftの比較
For ilnglLoop = 1 To 1000000
  strDummy = Left$(strData, 10)
Next ilnglLoop
ts_Watch "Left$で文字列型変数へ格納"

For ilnglLoop = 1 To 1000000
  varDummy = Left$(strData, 10)
Next ilnglLoop
ts_Watch "Left$でバリアント型変数へ格納"

For ilnglLoop = 1 To 1000000
  strDummy = Left(strData, 10)
Next ilnglLoop
ts_Watch "Leftで文字列型変数へ格納"

For ilnglLoop = 1 To 1000000
  varDummy = Left(strData, 10)
Next ilnglLoop
ts_Watch "Leftでバリアント型変数へ格納"


'Right$とRightの比較
For ilnglLoop = 1 To 1000000
  strDummy = Right$(strData, 10)
Next ilnglLoop
ts_Watch "Right$で文字列型変数へ格納"

For ilnglLoop = 1 To 1000000
  varDummy = Right$(strData, 10)
Next ilnglLoop
ts_Watch "Right$でバリアント型変数へ格納"

For ilnglLoop = 1 To 1000000
  strDummy = Right(strData, 10)
Next ilnglLoop
ts_Watch "Rightで文字列型変数へ格納"

For ilnglLoop = 1 To 1000000
  varDummy = Right(strData, 10)
Next ilnglLoop
ts_Watch "Rightでバリアント型変数へ格納"



その結果は次のようになりました。実行時間の単位は秒です。
使用関数 文字列型変数へ格納 バリアント型変数へ格納
Mid Mid$ 1.10 1.28
Mid 1.52 1.54
Left Left$ 0.82 0.94
Left 1.30 1.30
Right Right$ 0.83 0.95
Right 1.25 1.30
ご覧のように、微々たるものかもしれませんが、予想通り「いずれの場合にも$付き関数を使った方が高速である」ということが分かります。

さらにここでは、2つの着目すべき点があります。

1つは、同じ$付きの関数であっても、その返り値を格納する変数のデータ型によっても処理時間が変わるという点です。いずれも文字列型変数に比べて、バリアント型に格納する方が時間がかかっています。これは、VBAでは異なるデータ型の変数どうしの代入を行うと、暗黙的に代入先のデータ型に置き換えられるという特性の表れと考えることができます。$付きの関数は文字列型を返しますので、それを文字列型の変数に格納する場合にはデータ型の変換は必要ありません。一方、バリアント型に格納する場合には、文字列型→バリアント型の変換が暗黙のうちに行われていることになります。つまり、その型変換に要する時間が処理時間に余分に加算されているわけです。このことから、「同じ$付き関数を使った処理でも、代入先が文字列型でない場合には、データ型変換の分、処理時間がかかる」ということがいえます。

もう1つは、1点目と逆の話しになるのですが、$なしの関数を使った場合には、型変換の行われないバリアント型に代入するよりも、型変換の行われる文字列型変数に代入した方が高速であるという点です。おそらくこれは、バリアント型の返り値をバリアント型にメモリ上でコピーする処理よりも、文字列型への変換処理+コピーの処理の方が短時間ですむということなのでしょう。それくらいバリアント型変数の処理は遅いということもいえます。この点については、「$なし関数を使う場合は処理時間がかかるが、その返り値をバリアント型に代入するとさらに時間がかかる」ということがいえるでしょう。
| Index | Prev | Next |

 

Copyright © T'sWare All rights reserved