この特集のトップページへ

Visual Basicによるアプリケーション

 Visual Basicを利用してアプリケーションを開発する場合も,Accessを利用してアプリケーションを開発する場合と同様の考慮が必要となる。一般的に,開発されたアプリケーションの実行速度はコンパイラの生成する命令コード数とハードウェアのアーキテクチャに依存する。Visual Basicはバージョン4.0までP-codeと呼ばれる中間言語にコンパイルされ,その中間言語を解釈しながら実行する仕組みであったため,ほかのネイティブコードコンパイラで開発されたアプリケーションと比較すると処理速度で劣る場合があった。特に文字列処理では,その傾向が顕著であったといってよい。しかし,Visual Basic 5.0以降ではコンパイルモードがサポートされるようになったため,ネイティブコードコンパイラと遜色のない処理速度に改善されている。

 コンパイラが効率的な命令コードを生成するか否かは,アプリケーション開発者がどのような命令を利用してどのようなアルゴリズムでソースコードを記述するかによって異なる。Visual Basic 5.0であれば,アドインツールとして添付されているCode Profilerで性能を検証することができる*1。また,Transact-SQLステートメントをデバッグするならば,「Visual Basic T-SQLデバッガ」がアドインとして用意されている。

 Visual BasicでSQL Serverにアクセスするプログラムを開発しているときに性能改善を図るのであれば,次の点を検討する。

○トランザクションを使用する
 トランザクションを使用すると,更新データは一度バッファに格納され,CommitTransメソッドでコミットされて初めてディスクに書き込まれる。これにより,ディスクにアクセスする回数も減少して処理効率が向上するが,半面,メモリを消費する。また,トランザクション用のバッファ領域が不足すると内容が失われてしまうため,バッファ領域の大きさに合わせて,たとえば50レコードごとや100レコードごとにコミットしなければならない。

○カーソルはできるだけ使用しない
 カーソルは,結果セットの行を個々に参照する場合は非常に便利な機能であるが,メモリ,プロセッサ,ネットワークなどのシステムリソースを消費する。したがって,どうしても使用するのであれば,WHERE句にインデックス列を指定して少数のデータ行のみを取得し,結果セットをすぐにクライアントアプリケーションに渡すようにする。

○非同期処理を使用する
 Visual Basicアプリケーションの処理は,ほとんどが同期処理である。そのため,現在の処理が完了しない限り,次の処理へは進めない。非同期処理にすることで,アプリケーションに制御が即時に戻ってくるため,次の処理を並行して進めることができ,処理効率が向上する。RDOやADOといったAPIは非同期処理をサポートしているので,Visual Basicでアプリケーションを開発する場合は,できる限りこれらのインターフェイスを活用する。

○ストアドプロシージャを使用する
 クライアントアプリケーションのソースコードにTransact-SQLステートメントを挿入するのではなく,ストアドプロシージャやトリガを使用する。ストアドプロシージャは使用するたびにコンパイルする必要がなく,プロシージャキャッシュから直接実行できる場合が多いので,処理が高速になる。

○レコードセットを再度オープンする代わりにクエリを再実行する
 Cloneメソッドを利用すると,既存のRecordsetオブジェクトを高速にコピーできるため,新しいRecordsetオブジェクトを再度同じ定義でオープンする場合にも,このメソッドを利用すると新しいRecordsetオブジェクトを高速にオープンすることができる。しかし,最初のクエリを実行したあとで追加された新しいレコードもレコードセットに反映したい場合には,新しいRecordsetオブジェクトを作成するよりも,Requeryメソッドを使用するほうが高速に結果を取得できる。

○インデックスを指定する
 Sortプロパティによるソートは,レコード数が非常に少ない(100件以下)場合を除くと,処理速度が最も遅いソート手法である。インデックスを設定するか,テーブル型のRecordsetオブジェクトを利用しない場合には,ORDER BY句を指定したクエリを実行したほうが処理は高速になる。

○ブックマークを使用する
 Findメソッドなどを使用して元のレコードに戻るより,ブックマークを使用したほうがメモリは余計に必要になるが,高速にレコードを移動できる。

○パススルークエリを使用する
 Jetエンジンは,パススルークエリを使用すると,入力されたTransact-SQLステートメントをコンパイルせずに直接サーバーへと送信する。このため,更新・削除・追加を頻繁に実行する場合は,リンクされたサーバーのテーブルに対して通常のクエリを実行するよりも高速に処理できる。しかし,Jetエンジンを使用せずにRDOやADOを使用すると,Jetエンジンのオーバーヘッドがなくなるので,さらに処理効率が向上する。

○CacheStartプロパティ,CacheSizeプロパティ,FillCacheプロパティを使用する
 DAOとJetエンジンを組み合わせ,Recordsetオブジェクトを使用してSQL ServerにODBC接続する場合には,ローカルキャッシュ機能を利用することができる。特に,ダイナセット型のRecordsetオブジェクトを使用してデータを取得する場合には,CacheSizeプロパティ,CacheStartプロパティ,FillCacheプロパティを利用してローカルメモリに格納すると,性能が改善される。

○Seekメソッドを使用する
 DAOとJetエンジンを使用してレコードを検索するとき,Filterプロパティによる並べ替えは,レコード数が非常に少ない(100レコード以下)場合を除くと,最も処理速度が遅い並べ替え手法である。データを選択する場合は,テーブルを直接オープンして抽出条件にインデックス列を指定し,Seekメソッドを利用して選択レコードに位置付けると処理が高速になる。ただし,ODBC接続でSQL Serverにアクセスする場合には,Seekメソッド,Findメソッド,Filterメソッドを利用するのではなく,Transact-SQLステートメントのWHERE句を使用するほうがより高速に処理できる。

○非効率的なループ処理を削除する
 基本的に,プロパティを複数回使用することは避けるべきである。特に,ループ処理内で頻繁にプロパティの値を取得するような場合には,ループ処理外でプロパティの値を変数に代入し,その変数を利用したほうが処理は高速化される。また,SQLステートメントやストアドプロシージャで一括処理するほうがソースコードでループ処理するよりも高速に処理される。

○固有オブジェクト型を使用する
 変数や引数に固有オブジェクト型を使用すると,アプリケーションの実行時ではなくコンパイル時にオブジェクトへの参照が解決されるため,処理が高速化される。

○実行中変更しない文字列や数値は定数として宣言する
 変数として宣言すると,アプリケーションの実行時にその時点における値を取得するため,オーバーヘッドが生じる。しかし,定数として宣言することにより,アプリケーションのコンパイル時点で値が確定するため,実行時の処理が高速化される。

○StrCompプロシージャの代わりに等号(=)で比較する
 等号で比較すると,内部処理が少なくなるために処理が高速になる。StrCompプロシージャがループ処理内でくり返し実行されるような場合には,等号で比較することによって処理が高速化される(それ以外の場合ではあまり効果はない)。

○StrConvプロシージャの代わりにUCaseプロシージャやLCaseプロシージャを使用する
 大文字と小文字を変換する場合には,StrConvプロシージャではなくUCaseプロシージャやLCaseプロシージャを使用すると処理効率が向上する。

○動的な文字配列変数を使用する
 固定長配列は,処理速度が遅いうえにスタック領域を消費する。また,固定長配列では配列の各要素の値をクリアできるが,配列で使用しているメモリ領域は解放されない。これに対して動的な配列変数は,配列内のデータが不要になった段階でEraseステートメントやReDim Preserveステートメントを呼び出せば,データを削除したうえでメモリを解放することもできる。

○For Each ... NextステートメントやWith ... End Withステートメントを使用する
 1行または複数行のコードをくり返し実行するループ処理で,オブジェクトのコレクション中に要素がいくつ含まれているのかわからない場合には,Do ... LoopステートメントよりもFor Each ... Nextステートメントを利用したほうが効率的に処理される。

 また,同じオブジェクトを複数回操作する必要がある場合は,With ... End Withステートメントを使用すると実行時の処理が効率的になる。さらに,SwitchステートメントやChooseステートメントを利用するよりも,If ... Elseステートメントを利用したほうが処理は高速である。

○[コードの実行速度を最適化]オプションを選択する
 Visual Basicのプロジェクトプロパティには,コンパイルオプションとして[コードの実行速度を最適化]が用意されている。このオプションを選択すると,プログラムが要するメモリサイズの縮小よりも実行速度の最適化が優先される。
 ただし,プログラムのサイズが大きくなると,その分だけページングが発生する可能性も増大する。ページングの発生はディスクI/Oのオーバーヘッドに直結するため,状況によっては逆に処理速度が低下するおそれもあるので注意が必要である。

Fig.9-38 プロジェクトプロパティ


 Visual Basicプログラムのフォームの表示を高速化したい場合には,Accessを利用している場合と同じ方法が利用できる。しかし,フォームのロード時の高速化を問題にするのか,実行時の高速化を問題にするのかによって,方法が異なることに注意してほしい。具体的には,次のような点を検討する。

○AutoRedrawプロパティを適切に使用する
 AutoRedrawプロパティをオンに設定すると,そのフォームやコントロールのビットマップ情報をメモリ上に保存する。そのため,再描画するときには,そのビットマップ情報を使用して描画できる。半面,ビットマップをメモリに保存するため,ビットマップサイズが大きい場合には,メモリリソースを多量に消費する。再描画するときは,そのビットマップを画面にコピーするため,描画性能が低下することがある。

 AutoRedrawプロパティは,頻繁に変更しない複雑なグラフィックを描画する場合に限ってオンに設定し,頻繁に変更するグラフィックを描画する場合やグラフィックがないフォームを利用する場合には,必ずオフに設定する。

○Imageコントロールを使用する
 PictureBoxコントロールは別のウィンドウのなかに表示されるオブジェクトであり,ウィンドウとPictureBoxコントロールを使用して表示されたオブジェクトは,それぞれ別のフォームとみなされ,リソースを消費してしまう。クリックイベントやマウスイベントを識別するなどフォーム上に高度な機能を必要としない場合や,ピクチャを描画したいだけの場合は,Imageコントロールを使用するようにしたほうがよい。

○ピクチャの使用を最小限に抑える
 ピクチャのロードおよびアンロードには時間がかかり,アプリケーションの性能を低下させてしまうことがある。やむを得ずピクチャを利用する場合に実行速度を向上させたいのであれば,アプリケーションが複雑化してサイズも増加することを覚悟で,グラフィックをアプリケーション内に格納する。また,アプリケーション内の複数箇所でそのグラフィックを利用するのであれば,ダミーフォームを作成して利用すると,性能の劣化を抑えることができる。

○Lineメソッドを使用する
 線や図形を描画するPSetメソッドを利用するよりも,1回の操作で描画可能なLineメソッドを使用したほうが,描画の実行速度は向上する。また,Lineメソッドを利用するよりも,Windows APIのLineTo()を利用するほうがコードのステップ数は増えても実行速度は向上する。

○フォームは不要になったらアンロードする
 フォームをロードすると,フォームが表示されているか否かにかかわらず,かなりのメモリを消費する。特にフォームの数が多い場合や,コントロールやグラフィックの数が多い場合には,その影響は極めて大きい。そのため,不要になったフォームはUnloadメソッドを利用してメモリ上から完全に削除することが望ましい。

 しかし,Unloadメソッドでフォームを削除してしまうと,メモリを節約できる半面,再描画するときにはメモリ上にフォームを再ロードしなければならないため,時間がかかる。あとから再描画するフォームを一時的に画面上から消したい場合には,Hideメソッドを利用する。Hideメソッドはメモリ上にフォームを保存したままでフォームを画面から消去するため,再描画の実行速度は高速である。


  1. %VBroot%Tools\unsupport\vbcpフォルダに格納されている。
前へ Chapter 9 18/46 次へ