実践 クライアント/サーバーデータベースソリューション 第21回 最終回

第22回
ファイル共有型データベースとネットワークトラフィック

Access,VB6,Jetデータベースエンジンを利用した
C/Sシステム構築に関する考察,実験および実践



秋月巌ソリューション事務所
秋月 巌 AKIZUKI,Iwao



無償のソフトの増加により変化する状況

 さて、本連載は本筋からはずれた状況が続いている。しかし、興味深いテーマが多いので、今回はこの路線を継続しよう。何よりも、本筋を設定した連載開始当初とは、ローコストでクライアント/サーバーシステムを構築するための状況が大きく変化しているのである。
 現在、クライアント/サーバーシステムをローコストで作成する最善の方法は、Linuxサーバーとフリーのデータベースサーバーを使用することである。だがこの選択は、Visual Basicユーザーにとって馴染みのない多くのアイテムを使用する必要がある。
 Linuxという選択以外にもRDS(Remote Data Services)のリリース、そして再配布可能なMSDE(Microfoft Data Engine)の登場が、大きな状況変化の要因だということができる。

スレッド数の制限は何を意味するか?

 最近、MSDEは各誌でも取りあげられ始めた。この戦略的な製品の最大の懸念材料は、5つ以上のスレッドが作成できないという点に尽きる。これは5つ以上のクエリーが同時に発生した場合、同じスレッドに割り当てられたクエリーの待ち時間が増加することを意味する。注意してほしいのは、増加するのは待ち時間であって、処理時間ではないということである。
 MSDEの場合、次のようなケースを考えてみる。
 MSDEは5つ以上のスレッドを作成しないため、先のクエリーが実行されているスレッドの後端に作業を追加する。そのため、各種のオーバーヘッドが存在しないとしても、最後のユーザーは1分待たされた後で、さらに自分のクエリーを実行するために1秒の処理時間を待つことになる。結果、トータルで1分1秒の処理時間がかかることになる。
 MSDEの処理時間は、6人の合計で5分1秒なのにも関わらず、累積では6分1秒の待ち時間が発生する。もし、6つのスレッドが作成できるならば、処理時間も待ち時間も5分1秒で済むことになる。これが、マルチスレッドによる高速化の原理である。

すべては確率のための配慮

 ここでは1分のクエリーの例を使ったため差が極端なように感じられるが、多くのように瞬時で処理が終了するような場合には、体感的に問題はないし、サーバーの負荷という意味でも、別スレッドで実行した場合と比較して問題があるわけではない。つまり、シングルタスクで実行した場合や、MSDEのように十分なスレッド数が確保できない可能性があるような状況で利用する場合は、処理に時間のかかるクエリーは極力避けるべきだということである。これは処理に実行時間がかかる確率を低くするための配慮である。
 つまり、マルチスレッドは同時実行される並列処理を配分はするが、トータルの処理時間を短縮するのは、あくまでもマルチプロセッサを使用したときだけである。シングルプロセッサの場合、タスクスイッチによって切り替えているだけであり、理論的にはタスクスイッチのオーバーヘッド分だけ、処理速度は低速化する。

テクノロジーの進歩、そして確率

 ところで、最近のデータベースのソフトウェア的な意味での高速化の試みの多くは、処理時間が短くなる確率を上げるためのものである。一番明快な例として、キャッシュ機能をあげることができよう。キャッシュ機能は、一度実行されたクエリーの結果を保存しておいて、同じ要求が発生した場合、既存の結果を流用するデータアクセス高速化手法である。
 キャッシュはさまざまなレベルで行なわれる。結果データそのものを保持する場合もあるし、クエリーの構文チェック結果をキャッシュする場合もある。いずれにしても、最初に実行するときには処理結果をキャッシュするだけで、キャッシュされた結果を利用することはできない。また2度目以降でも、キャッシュされた結果が確実に保存されているという保証はない。結果セットが巨大である場合など、キャッシュされない場合もあるし、あるいはいったんキャッシュされても、それ以降にキャッシュされるデータが多くて、破棄されているかもしれない。当然、データベースサーバーやOSを再起動した場合などは、キャッシュの内容は破棄される。つまり、キャッシュによって処理が高速化されるか否かは、運まかせの部分があるということになる。

オプティマイザだってそうだ

 また、データベースサーバーのオプティマイザの進化なども、性能が向上する確率を上げるための手段である。
 データベースサーバーは、あるクエリーが実行されたときに、高速にデータベースにアクセスするための戦略をたてる。その判断の基準となるのが統計である。オプティマイザは統計情報を元にインデックスの使用の有無などを判断する。もちろん、統計に依存してたてる計画が常に正解であるとは限らない。結果として、オプティマイザの進化とは、天気予報の方法論の進化と似たようなものだ。当たる確率が上がるだけであり、決して確実な結果を得られるようになるわけではない。また、Microsoft SQL Serverのバージョンアップをみていても、オプティマイザの進化が常にデータベースの高速化につながるとは限らないことがわかる。
 大切なのはもともと高速な処理をより高速化することよりも、時間のかかる処理を高速化することにある。1秒かかる処理を10倍の性能で実行したとしても、短縮できる時間は0.9秒に過ぎない。だが、1分の処理時間を10分の1に短縮することができれば、その効果は54秒におよぶ。

データベースアクセスを本質的に高速化する方法

 データベースアクセスを本質的に高速化する方法として、
などがあげられる。本質的な高速化というのは、確実にその効果が期待できる方法のことである。

●ディスクアクセス

 キャッシュはディスクアクセスを高速化しているように見えるかもしれないが、これはディスクアクセスの回数を減らすだけであり、その効果も先に述べたようにその時点での状況に依存する。キャッシュを本質的な高速化手法とするには、アクセスするデータのすべてを起動時にメモリ上にロードし、かつ、それがアンロードされないように指定する必要がある。

●CPU

 CPUの高速化は時代がテクノロジーを牽引するのを待つことにしよう。もちろん、高価な予算を使って高速化処理装置を用意すれば、今日における最高水準までは性能を確保することができる。
 また、CPUの数を増やすことは、パフォーマンス向上の王道だということができる。しかし、400MHzのCPUがふたつあるからといって、800MHzのCPUになるわけではない。
 ここでマルチスレッドが意味をもってくる。各スレッドごとに別のCPUが処理を行なえば、CPUひとつあたりのタイムシェア時間は削減する。

●検索アルゴリズム

 検索アルゴリズムについては、現在のインデックスの実装方法はすでに完成の域に達しているということができる。インデックスによる検索の高速化も、基本的にディスクアクセスの回数を減らすことによって実現する高速化手法である。テーブルよりもサイズの小さいインデックスファイルに効率的にアクセスすることで、劇的にディスクアクセスの回数を減らすことができる。これはキャッシュとは違い、常にその効果を期待することができる。
 トレードオフとして、使用するディスク容量の増加と、データの追加更新時のパフォーマンスが悪くなる可能性があることがあげられる。このトレードオフの検討は、データベースなどの解説書では、例外なく解説されているが、実際の使用においてはメリットがデメリットを上回るケースがほとんどである。
 インデックスを使用するメリットのないようなテーブルにインデックスをつけたとしても、このようなケースではテーブルのサイズ自体が大きくないことが多いので、パフォーマンスの劣化はほとんど認識できない程度でしかない。また、データサイズの増加も大きな問題とはならないだろう。

メリットがデメリットを上回るインデックス

インデックスは、1害はあるが100利ありといえるほどメリットが多いので、積極的に使用するべきである。もちろん、巨大なテーブルに使用しないインデックスを設定したりするのは、メリットとデメリットの比較ではなく、単なる使い方の間違いなので避けなければならない。つまり、判断すべきなのはインデックスを使うか使わないかということよりも、適切なインデックスをどのように設定するかということである。

Remote Data Servicesと疑似セッション

 RDSのコンセプトは、本連載のDB Serverのコンセプトに類似している。独自サーバープログラムの代わりに、IISを使うというだけのことである。データ更新のメカニズムとしては、サーバー側のレコードセットをコピーしたクライアント側のレコードセットにより、クライアントカーソルを実現している。結果として、セッションレスの動作が可能である。というよりも、データの転送にWebサーバーを使用しているため、セッションをできなかったという事情がある。ネットワーク的にはセッションを切断しているが、サーバー側の疑似セッション機能を使用することで、ステートの維持を実現している。
 Active Server Pagesもそうなのだが、疑似セッションの最大の問題は、サーバー側がセッションの終了を判断するために、タイムアウトを使用せざるを得ないということにある。RDSはサーバー側でのCOMコンポーネントの実行をクライアントから指示できるなど、優れた点が多い。ADCと呼ばれていたころと比較して、パフォーマンスも安定性も格段に向上している。実用の域に達したといっていい。
 MicrosoftはRDSを、データベースをWebに対応させるためのコンポーネントという見せ方をしているが、Jetデータベースエンジンのようなファイル共有型データベースをデータベースサーバーとして動作させる二次的な効用があることを忘れてはならない。この点が本連載のDB Serverと共通しているのである。

ファイル共有型のデータベースは遅いのか?

 話は戻って、本連載の主旨は安くて高速なクライアント/サーバーデータベースシステムを構築することであった。クライアント/サーバーシステムを採用したのは、連載開始当時の時代背景を考えての配慮である。今月は原点に返って、クライアント/サーバーシステムは、本当に高速なのか、ということを検証したい。これはいい換えれば、ファイル共有型のデータベースアクセスは、本当に遅いのかというテーマと一致する。

ダウンサイジングとクライアント/サーバーシステム

 本来、クライアント/サーバーシステムというのは、汎用機などの中央集権的なシステムに対するアンチテーゼとして生まれた発想である。現在のキーワードで表現すれば、Windows-Based Terminalのような(真の)クライアントシステムに対応する。これらのシステムの最大の問題点は、サーバーに負荷が集中するため、高速に処理を実行するためには、サーバーのスペックに要求されるものが高くなるということがある。
「高速なコンピュータを1台作るよりも、その10分の1の性能のコンピュータを10台作る方が、はるかにコストが低い」といのが、現在のハードウェア産業である。ならば、「10台の端末が接続されるならば、それぞれのクライアントが処理を負担してくれれば、システムトータルでの性能は向上する」というのが、ダウンサイジングを正当化する根拠である。

ダウンサイジングはアップサイジング

 しかし、パーソナルコンピュータからみると、ダウンサイジングの流れはアップサイジングの流れだった。DelphiとParadox(それにInterBase)をもつBorland社(現INPRISE社)は、当時、アップサイジングカンパニーを標榜していた。パーソナルコンピュータのデータベースアプリケーションは、xBASEやBtrieveなどのファイル共有データベースが主流だった。だから、データベースサーバーを使用するクライアント/サーバーシステムへの移行は、ダウンサイジングではなくアップサイジングだったのである。

ファイル共有型とサーバー型の違いについて

 ファイル共有型データベースとサーバー型データベースのアーキテクチャ上の違いについては、本連載でも説明したし、本誌11月号の特集記事「パケットで知るデータベース」(P55)でも説明されているので参考にしていただきたい。
 ファイル共有型とサーバー型には表1のような特徴がある。
 負荷の分散を目指したクライアント/サーバーシステムだが、サーバーから分離されるのはあくまでもビジネスロジック部であり、データベース処理は一括してサーバーが受けもつ。ファイル共有型は、データベース処理までもクライアントに分散される。ネットワーク負荷が増大するのは、データベースアクセスに必要なファイルアクセスが、すべてネットワーク経由で行なわれるためである。
 結果的に、クライアント/サーバーシステムと異なり、ファイル共有型ではデータベースアクセスの処理能力そのものが、各クライアントコンピュータの性能に依存する。しかし、今日のようにクライアントコンピュータの性能がサーバーマシンと大差がないような状況では、クライアントに負荷を依存する有効度は大きい。

表1:ファイル共有型とサーバー方の特徴

長所 短所
ファイル共有型 負荷の分散 ネットワークトラフィックの増大
サーバー型 負荷の集中 ネットワークトラフィックの最適化

プリンタサーバーはクライアント/サーバー型

 プリンタサーバーを考えてみよう。プリントサービスは十分に負荷の大きいサービスだ。各クライアントはプリントサービスをサーバーに送信すると、処理から開放される。プリンタサーバーはクライアントから依頼された処理を順にこなしてゆく。プリンタが1台しかないならば、それは1スレッドしか使用できないクライアント/サーバーモデルということができる。これが、もし各クライアントにプリンタが接続されていれば、それぞれのクライアントが勝手に印刷処理できるため、全体での処理能力は向上する。

検索回数によるネットワークトラフィックの差

 ならば、ファィル共有型データベースのネットワークトラフィックが最適化できれば、クライアント/サーバーシステム以上の性能が確保できることになる。今回はその可能性について検証しよう。 表2は、10Byteのフィールドが108フィールドある10,000レコードのテーブルがあるリモートMDBファイルに対して、検索を実行した場合のトラフィック量を示したものである。検索結果は1レコードになるように検索引数を設定している。MDBのサイズは20.082MBほどになる。テーブルはAccess 97で作成し、最適化を施してある。
 インデックスを使用していないため、1回目の検索ではファイルとほぼ同サイズのデータがネットワークを流れている。単一フィールドのみに対して検索を行なったにも関わらず、すべてのフィールドのデータをファイルサーバーから取得したことになる。
 2回目以降は、7回目まで回を重ねるごとにトラフィック量が減少している。これはテーブル全体がキャッシュされたものと考えることができる。もちろん、体感上の検索速度も回を追うごとに向上する。8回目以降は値を変更して検索を実行した。いったんトラフイック量が若干増えるものの、それ以降は収束する。結果として、キャッシュは検索結果をキャッシングしているのではなく、テーブル全体をクライアント側にキャッシュしていることがわかる。
 なお、1回目の検索のトラフィックは、検索結果となるレコードがテーブル上のどの場所にあるかに依存することなく、同等の値を示した。これは検索する項目がユニークに設定されていないからである。

表2:約20MBのMDBのリモートファイルをスキャンする場合のトラフィック量
実行回数 トラフィック量(KB)
1回目 20,849
2回目 6,632
3回目 2,317
4回目 609
5回目 467
6回目 349
7回目 311
8回目(検索引数を変更) 508
9回目 353
10回目(変更した検索引数で再度実行) 852

インデックスを用いた場合のネットワークトラフィック

 表3は、同じテストをインデックスを用いて検索した場合のトラフィック量である。総体的にトラフィック量が激減していることがわかる。2回目以降は何度繰り返してもほとんど変わらない値だった。値を変更すると(表3の3回目)、トラフィック量が1回目と同等に戻ったが、それ以降は値を変更してもトラフィック量は0のままだった。これは、インデックスデータそのものをキャッシュした結果だと考えることができる。
 試しに1回目の検索を実行した直後にファイルサーバー側でデータを変更して、再度、検索を実行すると、変更が反映されないことがあった。ファイルクライアントにあるキャッシュデータを使用するために、ファイルサーバーの内容の変更が検知できないのである。しかし、検索を繰り返すと、適当なタイミングで変更がクライアントにも反映された。
 ふたつのフィールドをインデックスとして指定する多重インデックスを使用して検索した場合のトラフィックは、77KBだった。インデックスのサイズは直接的にトラフィックに影響を与えるわけではないようである。
 ちなみにインデックスを作成するために発生したトラフィックは21,076KBであり、ほぼ、全データをリモートファイルサーバーから取得したことになる。

表3:表2のデータをインデックスを用いて検索した場合のトラフィック量
実行回数 トラフィック量(KB)
1回目 91.942
2回目 0.354
3回目(検索引数を変更) 90.762
4回目(変更した検索引数で再度実行) 0

データ変更時のネットワークトラフィック

 表4は、データを変更した場合のトラフィック量である。計測用に20のフィールドに対して別々のインデックスを設定した。1フィールドを変更しただけの23KBに対して、5フィールド変更した場合は132KBのトラフィックが発生した。どちらも変更したレコードはひとつだけで、更新したフィールドにはインデックスが設定されている。インデックス更新のためのトラフィックが、更新したフィールド数に比例して増大している。

表4:データを変更した場合のトラフィック(20の項目にインデックスを設定)
変更したフィールド数 トラフィック量(KB)
1フィールド 23
5フィールド 132

データ追加時のネットワークトラフィック

 表5に、設定したインデックスの数とデータ追加時のトラフィックの関係を示した。1フィールドだけにインデックスを設定した場合はインデックスなしの場合と大きな差がないが、20のインデックスを設定した場合には、追加したインデックス数に比例する以上にトラフィックが増加していることがわかる。インデックスの数がそのままコストに結びついているのである。

表5:インデックスの数とデータ追加時のトラフィックの関係
追加データ数 トラフィック量(KB)
インデックスなし 15
1フィールドにインデックスを設定 20
20フィールドにインデックスを設定 510

データボリュームの差とネットワークトラフィックの差の関係

 表6は、データボリュームとインデックスの有無の関係を明確にするために、レコード数をこれまでより25倍の250,000レコードに増やして確認した結果である。インデックスなしの場合は追加したレコード数に比例するトラフィックが発生したが、インデックスを使用した場合は30%程度しか増加しなかった(表3参照)。データサイズが大きいときほど、インデックスの効果が大きくなることがわかる。

表6:250,000レコード(25倍)で検索を実行したときのインデックスの有無によるトラフィックの差

インデックスあり インデックスなし
トラフィック量 122KB 535,622KB

Access 2000ではMDBのサイズが倍になる

 これらの計測は、すべてAccess 97で作成したMDBファイルを使用した。最初はAccess 2000を使うつもりだったが、同じサイズのテーブルを作成してもAccess 2000を使うとMDBのサイズが倍になるため変更したのである。10Byteのフィールドが108、レコード数が10,000の場合、Access 97では20.082MBなのに対して、Access 2000の場合は40.116MBになる。この調子で250,000レコードのテーブルを作成することは、テストのためのリソースの制限からいって難しかったのである。

トラフィック量はファイルIOの量

 ここで紹介したトラフィック量は、そのままファイルIOの回数だと判断することもできる。リモートサーバーは、あくまでもファィルサーバーだからである。ファイルIOが少ないデータベースシステムは、そのまま高性能なデータベースシステムだということができる。トラフィックを削減する設計はネットワークを使用していなくても高速なのである。
 今回の結果から、高速なデータベースアクセスを実現するための設計のヒントが得られるはずである。ひと言でいってしまえば、フィールド長とインデックスの設定である。適切なフィールドに適切なインデックスを設定することで、トラフィック(ファイルIO)は劇的に低減する。
 あまりにも当たり前の結論だが、それを量的に確認できたことが、今回の成果だということができる。

サーバー型データベースとの比較

 インデックスをキャッシュした場合を除いて、トラフィック量は常にKB単位で発生した。これはサーバー型データベースを使用した場合と比較して、1桁多い値である。しかも、サーバー型データベースの場合、データの量が増加しても検索ヒット数が変わらない限りこのトラフィック量の値は増加しないが、ファイル共有型データベースの場合は増加する。もっとも、その増加の割合は、インデックスを使用した場合、データボリュームの増加と比較すればかなり小さい(表3と表6を比較)。
 また、ローカルネットワークの場合、数十KB程度のトラフィックがもたらすパフォーマンスの影響は、あまり気にならないだろう。そして、クライアントマシンの性能が高ければ、処理を分散する効果がトラフィックの多さを補う可能性もある。結局、優劣はケースバイケースということになるだろう。高速なネットワークでデータボリュームが小さく、そしてサーバーマシンとクライアントマシンの性能差が小さく(あるいはクライアントが高速)、かつアクセス頻度が高い場合には、ファイル共有型の方が有利になる可能性は十分にある。
 ただ、実際に市販されているサーバー型のデータベースは、そういったパフォーマンスのためのアーキテクチャの差以上に、動作の安定性や耐障害性に対する優位性がある。ファイル共有型のデータベースでは、構造上、パフォーマンスを維持しながら、耐障害性を確保するのは難しい。


VB Magazine ライブラリ| Visual Basic WorkGroup
int21 ホームページ| PCDN ホームページ

PCDN
Copyright (c) 1998 int21 CorporationAll Rights Reserved.
For questions or comments, please send mail to: pcdn@int21.co.jp