観(み)ることで見えてくるデータベースの仕組み

パケットで知るデータベース

初音 玲 HATSUNE, Akira



SQL文を知っていれば、多少の方言に悩まされたりするときもあるが、比較的簡単にRDBMSからデータを引き出したり、加工したりすることができる。このことから、SQL文が使えればRDBMS製品は何でも良いのではないかと思ってしまう人もいるようだ。そうなってくると製品特性による比較からではなく、自分が普段慣れ親しんでいる製品かどうかでRDBMSを選択してしまうこともある。そして、その「慣れ」が正規化などの充分な検討を経ずにプロトタイピング手法的にテーブル構造を決定してしまうことに繋がるときもあるようだ。「とりあえずテーブル作っておいたから、それを元にしてプログラムを作って欲しい」というような依頼は、RDBMSのテーブル設計に精通した業務担当者にのみ許される特権だということを再認識して欲しい。テーブル設計に疎い業務担当者にも業務に疎いシステム設計者にもその特権は許されてはいない。許されていない特権を行使すれば、そこに待つのは「玉砕」という2文字でしかない。

観(み)るということ

 私は、箱庭というか風景模型、いわゆるジオラマをぼーっと眺めているのが好きだ。別に鉄道模型のように、そこには動きがなくてもよい。そして、ジオラマでなくても航空写真や住宅地図なんかでもよい。とにかく俯瞰した画像として、精巧な風景が眺められれば幸せなのだ。そのとき、私の脳みそは、その画像の中を自在にウォークスルーするために極めて高度な演算を高速に行なっていることになる。
 同様にLANに流れるパケットを理解することにより、ハブのランプの点滅からパケットの状況が頭に浮かぶようになってくる。今回は、有限会社レイヤー社製のシェアウェアであるLANパケットモニタ“PacMon”(注)を使い、LAN上に流れているパケットの情報を取得(図1)して、RDBMS製品の特性を見てゆきたいと思う。

図1:PacMonでパケット情報を取得する
図1:PacMonでパケット情報を取得する

注)有限会社レイヤー
URL=http://www.layer.co.jp/
PacMon=価格:10,000円(手数料・税別)/1ユーザーライセンス

SMBを観(み)る

 マイクロソフトネットワーク(たとえば、Windowsドメインやワークグループ)に参加しているとSMB(Session Message Block)プロトコルのパケットがネットワーク上を時々流れる。このSMBプロトコルがなかなかの曲者で、ISDNルータなどを導入したときに、ISDNの向こう側にあるWindowsドメイン、BDC(Backup Domain Controler)またはマイクロソフトネットワーククライアントとの間でデータの送受信が行なわれ、気が付かないうちに電話代が跳ね上がっているなどということが発生する。
 このSMBプロトコルの実体とは、NetBIOSプロトコルである。そして、NetBIOSプロトコルは、最初はNetBEUIプロトコルを使って実現されるプロトコルだったが、現在では、TCP/IPプロトコルやUDP/IPプロトコルを使って実現することもできる(図2)。いわゆるNBT(NetBIOS over TCP/IP)だ。NetBEUIプロトコルをISDNルータで禁止しても、このNBTがISDNルータを機能させてしまう。ISDNを介したファイル共有やプリンタ共有を行なわないのであれば、NBTが使っているポートをISDNルータで禁止するのがよいだろう。NBTが使用しているポートは、

(1)NetBIOS-NS (ポート番号 137)
(2)NetBIOS-DGM(ポート番号 138)
(3)NetBIOS-SSN(ポート番号 139)
の3つだ。
 もう少し詳しく解説すると、NetBIOS-NSは、名前解決のためのプロトコルであるので、何もしないでいれば発生しないデータだ。しかし、NetBIOS-DGM(図3)とNetBIOS-SSN(図4)は違う。この2つは、何もしないでいてもマイクロソフトネットワークにログインしていれば定期的に発生する。これは、サーバーサービスを起動しているWindows NT、ネットワークの設定で「ファイルとプリンタの共有」をチェックしているWindows 95やWindows 98が随時送信しているものだからだ。とくにNetBIOS-SSNは、ファイル共有するためのプロトコルなので、マイクロソフトネットワークに含まれるマシン間で1対1に共有情報をやりとりしていたりする。つまり、あまり気にせずに、または「他のマシンの共有フォルダを使うのに必要だ」と勘違いしてWindows 95/98のネットワークの設定で「ファイルとプリンタの共有」をチェックしてしまうことは、ネットワークのトラフィックを増加させることにほかならないのだ。

図2:マイクロソフトネットワークの階層図
図2:マイクロソフトネットワークの階層図

図3:NetBIOS-DGMのパケット情報の例
図3:NetBIOS-DGMのパケット情報の例

図4:NetBIOS-SSNのパケット情報の例
図4:NetBIOS-SSNのパケット情報の例

ファイルサーバー上のmdbファイルを開く

Accessを使って開く

 まずは、ファイルサーバーの共有フォルダにあるmdbファイルをダブルクリックして、拡張子に結び付けられているAccessを自動起動してみる。
 まず、ここできちんと理解しておかなければならないのは、ファイルサーバーの役割と拡張子に結び付けられているアプリケーションの関係だ。Accessをファイルクライアントで起動して、[ファイル]-[開く]メニューでmdbファイルを開いたとしたら、Accessが動作しているのはファイルクライアントであることは理解しやすいだろう。
 Windowsでのファイル関連付けというものが、このアプリケーション起動から[ファイル]-[開く]メニューをクリックするまでの一連の操作を簡略化するものだということがわかっていれば、勘違いは起こらない。しかし、そういった隠蔽されたベースとなる技術を知らずに使っている人の中には、ファイルサーバー上でmdbファイルをダブルクリックすると、ファイルサーバー上でAccessが動作すると理解している人がいるが、これは大変な誤解である(図5)。
 さて、この形態でmdbファイルを使うとどのようなデータがLAN上を流れるのだろう。さっそく、パケットモニターでデータを取得してみる。mdbファイルを開くまでにいくつかのパケットがやりとりされているが、それを図6にまとめてみた。結論としては、mdbファイルがAccessから使われるときは、ファイル全体がファイルサーバーから読み込まれるということだ。

図5:ファイルサーバー上のmdbファイルを使う
図5:ファイルサーバー上のmdbファイルを使う

図6:mdbファイルを使ったときのパケット
図6:mdbファイルを使ったときのパケット

Visual Basicを使って開く

 さて、次にVisual BasicからDAO/Jetを使ってファイルサーバーの共有フォルダにあるmdbファイルを開いてみる(リスト1、図7)。その過程で、リスト1のそれぞれのポイントでどのようなパケットが流れていたかを表1にまとめてみた。
 注目すべきは(2)のOpenRecordsetメソッドの実行で、ファイルサーバーからすべてのデータが取得され、(3)や(4)といった、レコード値の取得やレコードの移動が行なわれているところでは、ファイルサーバーにデータを取得に行かないということ。これはいわゆるファイルキャッシングのようなものだ。
 この方式ならば、OpenRecordsetが完了してしまえば、あとはメモリに読み込まれたデータを取得してくるだけなので、非常に高速な動作が行なえる。1台のファイルクライアントからmdbファイルを使うときには、mdbファイルがローカルディスクにあるときに比べて、OpenDatabaseメソッドやOpenRecordsetメソッドの実行に時間がかかる以外は、この方式で何も不都合はないだろう。
 しかし、複数のファイルクライアントからmdbファイルを同時に使ったときにはどうなるだろう。どのクライアントがmdbファイルを使っているかは、ldbファイルの中身をみれば識別でき、また更新しているページの情報も含まれているらしい(リスト2)。つまり、複数のファイルクライアントが唯一お互いの情報を識別できるファイルサーバー上には、その程度の情報しか管理されていないのだ。

図7:mdbファイルを使うVBサンプル
図7:mdbファイルを使うVBサンプル

リスト1:mdbファイルを使う(frmMDBからの抜粋)
Set dbsMDB = Workspaces(0).OpenDatabase(txtFile.Text, , False) ・・(1)
strSQL = txtSQL.Text
Set rdynMDB = dbsMDB.OpenRecordset(strSQL, dbOpenDynaset)・・・・・(2)
Do While Not rdynMDB.EOF
  strResult = ""
  For iintCol = 0 To rdynMDB.Fields.Count - 1
      strResult = strResult & _
                  rdynMDB.Fields(iintCol).Value & vbTab・・・・(3)
  Next
  lstResult.AddItem strResult
  rdynMDB.MoveNext ・・・・・・・・・・・・・・・・・・・・・・・・(4)
Loop
rdynMDB.Close・・・・・・・・・・・・・・・・・・・・・・・・・・・(5)
dbsMDB.Close ・・・・・・・・・・・・・・・・・・・・・・・・・・・(6)

リスト2:ldbファイルの中身
YAMAHA                          Admin

表1:mdbファイルを使ったときにやり取りされるデータ
プログラムコード LAN上を流れるデータ 備考
(1) テーブル名などの管理情報  
  ldbファイルの作成
 
(2) empテーブルのデータ 図8
(3) (特になし)  
(4) (特になし)  
(5) (特になし)  
(6) ldbファイルの削除 図9

図8:OpenRecordsetメソッド実行時のデータ
図8:OpenRecordsetメソッド実行時のデータ

図9:closeメソッド実行時のデータ
図9:closeメソッド実行時のデータ

Visual Basicを使って更新する

 このような状態だと、同時に更新を行なったときには正しく動作するのか非常に不安に感じる。その不安を解消するには、取得したデータを更新するときには、どのようなことが起こっているかを確認するに限る(サンプルmdb_upd・リスト3)。結論としては、(5)のUpdateメソッド実行時に更新があったページをファイルサーバー上のmdbファイルに転記するだけだ(表2・図10)。また、Editメソッド〜Updateメソッドの間でもldbファイルに更新するテーブルやレコードの情報が格納されることはなかった。

リスト3:mdbファイルを更新する(frmMDBUpdからの抜粋)
Set dbsMDB = Workspaces(0).OpenDatabase(txtFile.Text, , False)・・(1)
strSQL = txtSQL.Text
Set rdynMDB = dbsMDB.OpenRecordset(strSQL, dbOpenDynaset)・・・・ (2)
If Not rdynMDB.EOF Then
  rdynMDB.Edit・・・・・・・・・・・・・・・・・・・・・・・・・・(3)
  rdynMDB.Fields(0).Value = 0 ・・・・・・・・・・・・・・・・・・(4)
  rdynMDB.Update・・・・・・・・・・・・・・・・・・・・・・・・・(5)
End If
rdynMDB.Close ・・・・・・・・・・・・・・・・・・・・・・・・・・(6)
dbsMDB.Close・・・・・・・・・・・・・・・・・・・・・・・・・・・(7)

表2:mdbファイルを更新したときにやり取りされるデータ
プログラムコード LAN上を流れるデータ 備考
(1) テーブル名などの管理情報  
  ldbファイルの作成  
(2) empテーブルのデータ  
(3) (特になし)  
(4) (特になし)  
(5) 更新があったレコードが含まれるページのデータ 図10
(6) (特になし)  
(7) ldbファイルの削除  

図10:Updateメソッド実行時のデータ
図10:Updateメソッド実行時のデータ

Visual Basicを使って同時更新する

 しかし、これはおかしい。Editメソッド実行時に何もパケットが発生しないのならば、同時更新したときに、図11のようなエラーはどうやって発生させているのだろう。
 実は、表2の測定をしたときには、プログラムを1本しか稼動させていなかった。つまり、ldbファイルには1マシン名しか格納されていなかったのだ。そこで、複数のファイルクライアントから同時更新を行なってみると、ldbファイルには複数のファイルクライアントの名前が格納され、そのときにファイルサーバより先に使っていたファイルクライアントにLOCKING_ANDXのリクエストが届く。この仕組みにより、同時更新の可能性を各ファイルクライアントが認識するのだ。そして、Editメソッド実行時に図12のようにSMBレベルでmdbファイルのページロックエラーが返却され、それに続いてロックしている相手も返却されてくる。あくまでもファイルI/Oレベルでのロック対策がとられているということだ。
 また、このことからわかるのは、mdbファイルを1プログラムから使っているときと、複数プログラムから使っているときでは、Editメソッドの動作がまったく異なっているということだ。LAN上に流れるパケット量すらも変化するということは、参照だけだとしても処理速度やLANのトラフィックの増加が発生するということだ。ldbファイルができなければよいのだが、排他モードでOpenDatabaseメソッドを実行することになり、これだと複数のプログラムから同時参照すらもできなくなるので、本末転倒だ。
 これはなかなかの盲点ではないだろうか。テストだとそこそこのスピードを確保しても何台かのマシンでファイル共有すると思ったほど速度が出ないという状況が考えられる。そうなってくると、同時更新だけではなく同時参照を行なうようなシステムでも問題を抱えることになる。

図11:同時更新時のエラー
図11:同時更新時のエラー

図12:SMBのLOCKING_ANDXのエラー
図12:SMBのLOCKING_ANDXのエラー

Visual Basicを使って更新する2

 さて、ついでにOpenRecordsetメソッドのOptionパラメータにdbSeeChangesを指定して更新してみたときも調査してみる(リスト4)。
 するとdbSeeChangesを指定しなかったときには、発生しなかったeditメソッド実行時のデータのやりとりが発生していることがわかった(図13)。このデータの内容は、更新対象となったレコードが含まれるページを再度読み込んでいるものだ。そして、ほかから更新されたことが通知されるのではなく、OpenRecordsetメソッド実行時と内容が異なっていれば、図14のようなエラーがクライアント上で動作しているプログラムで発生するという仕組みだ。よって当然のことながら、OpenResultsetメソッドからEditメソッドの間に他から複数回の更新が発生した結果、レコード値が元に戻っていたときには、dbSeeChangeを指定してもエラーは発生しない。

リスト4:mdbファイルを更新する(frmMDBUpd2からの抜粋)
Set dbsMDB = Workspaces(0).OpenDatabase(txtFile.Text, , False) ・(1)
strSQL = txtSQL.Text
Set rdynMDB = dbsMDB.OpenRecordset(strSQL, dbOpenDynaset, _
                                           dbSeeChanges) ・・・・(2)
If Not rdynMDB.EOF Then
    rdynMDB.Edit ・・・・・・・・・・・・・・・・・・・・・・・・(3)
    rdynMDB.Fields(0).Value = 4444 ・・・・・・・・・・・・・・・(4)
    rdynMDB.Update ・・・・・・・・・・・・・・・・・・・・・・・(5)
End If
rdynMDB.Close・・・・・・・・・・・・・・・・・・・・・・・・・・(6)
dbsMDB.Close ・・・・・・・・・・・・・・・・・・・・・・・・・・(7)

図13:Editメソッド実行時(dbSeeChange指定)のデータ
図13:Editメソッド実行時(dbSeeChange指定)のデータ

図14:Editメソッド実行時のエラー
図14:Editメソッド実行時のエラー

同時mdbファイル更新に対する見解

 LANアナライザでファイルサーバーとファイルクライアント間でやりとりするデータをいろいろ見てきたが、mdbファイルの同時参照はまだしも、同時更新時の動作というのは非常に心もとない技術のうえに立脚していると言えるだろう。とてもじゃないが、重要なデータを扱う気にはなれない。
 もし、現在このような形態のシステムを作成しているならば、同時更新が行なわれないような運用上の工夫やプログラムの工夫、たとえば、OpenRecordsetメソッドのoptionパラメータにdbDenyWriteを指定して同時更新を防ぐことや、dbDenyReadを指定して、更新中はデータの参照を防止するなども必要になってくる。

OracleをDAO/Jetで使う

 DAO/Jetを使ってOracleと接続する方法は、大きく分けて2種類存在する。

(1) DAO/Jetを素直に使う
(2) SQLパススルーを使う
 通常、SQLパススルーを使って作成したレコードセットを更新することはできないが、レコードセット作成の性能がよいといわれている。
 それはどうしてなのだろう。実際にLANに流れるデータを観ることで何かがわかるかもしれない(サンプル:DAO)。

DAO/Jetを素直に使う

 DAO/Jetを素直に使ったとき、OpenRecordsetメソッドを使うと15パケットの送受信が発生した(図15)。いつも15パケットとは限らないが、サンプルプログラムを使って、Oracleのサンプルテーブルであるemp表を取得したときには、いつも15パケットであった。内容的には、画面上で指定した

SELECT * FROM emp

というSQL文の送信にたどり着くまでに、図16のようなSQL文を発行してテーブル名などを取得していたりする。これは、DAO/Jetが指定されたSQL文を解析するのにテーブル名やフィールド名の情報を事前にDAO/Jetが管理するクライアント側に取得してこなければいけないからだ。
 DAO/Jetを使うということは、このようにOracleのテーブル情報などをクライアント側で管理し、その管理している内容に基づきDAO/JetがSQL文を解析して、ODBCデータソース(今回はOracle)にあったSQL文を自動生成するということだ。
 だからこそ、ODBCデータソースの違いをDAO/Jetがすべて吸収することができ、理論的には同じSQL文であらゆるODBCデータソースを扱うことができる。しかしながら、RDBMSごとのSQLチューニングが事実上できないことやテーブル情報などの多重管理に伴うオーバヘッドなどの問題も含んでいる。

図15:OpenRecordset(DAO/Jet→Oracle)
図15:OpenRecordset(DAO/Jet→Oracle)

図16:DAO/Jetにより自動発行されたSQL文
図16:DAO/Jetにより自動発行されたSQL文

SQLパススルーを使う

 DAO/Jetでレコードセットを管理することを放棄することで、DAO/Jetを使っていても劇的にパフォーマンスを向上させる方法がSQLパススルーだ。
 SQLパススルーを指定したOpenRecordsetメソッドでは、全部で3パケットの送受信しか起こらなかった(図17)。また、

(1) 指定したSQL文がそのままOracleに送信される
(2) 複数レコードを取得する(図18)
などがSQLパススルーを指定しなかったときと異なっていた。
 とくに(2)は、LANに流れるデータを確認するまでは気が付かなかった点だ。このようなデータの送受信が行なわれるとすれば、RDBMSごとのSQLチューニングも可能であるし、レコードセットのMoveNextなども高速に行なえることがうなづける。反面、レコードセットに対して更新できないこととともに、ODBCデータソースごとにSQL文を検討しなければいけないので、「あらゆるODBCデータソースに接続可能」というDAO/Jetの利点はなくなってしまうことも心に留めておきたい。

図17:OpenRecordset(SQLパススルー)
図17:OpenRecordset(SQLパススルー)

図18:SQLパススルーでのデータ取得例
図18:SQLパススルーでのデータ取得例

OracleをRDOで使う

 DAO/Jetは、本来mdbファイルを読み書きするための仕組みだ。よって、RDBMSと接続するときには、余計な処理が介在したり、SQLパススルーのように苦肉の策を講じなければならない。そこで、Microsoftが提唱しているRDBMS接続用のミドルウェアであるRDOを使ってみる。
 RDOには、ODBCカーソル、Serverカーソル、Batchカーソルの3種類のカーソル制御の方法がある。カーソル制御とは、処理する行を管理する機能だ。メソッドに対するパケット数をカーソルごとにまとめたものが表3だ。
 Serverカーソルは、何かパラメータの指定が悪いのかもしれないが、今回深くは追求しないことにした。正常に動作するODBCカーソルとBatchカーソルについて、どの動作の違いをLANに流れるデータから検証してみる。
 この2つのカーソルの違いは、OpenResultsetメソッドの実行時に発生する。ODBCカーソルがレコードのデータだけを取得しているのに対して、Batchカーソルはテーブルの構造までも取得していることがわかった(図20)。このテーブル構造を踏まえて、Batchカーソルではクライアント側での擬似的なテーブルを管理し、最終的には、BatchUpdateメソッドにより、一気にRDBMSを更新するという処理を可能にしている。
 なお、両者ともにMoveNextメソッド実行時にパケットが発生していないのは、レコードのキャッシュ機能により、あらかじめ次レコードのデータがメモリ上に読み込まれていたからだ。

表3:RDOのパケット数
  ODBCカーソル Serverカーソル Batchカーソル
EstablishConnection 30 30 30
OpenResultset 5 図19 15
MoveNext 0 0

図19:RDO-Serverカーソルで発生したエラー
図19:RDO-Serverカーソルで発生したエラー

図20:OpenResultset(Batchカーソル)実行時のパケット
図20:OpenResultset(Batchカーソル)実行時のパケット

OracleをADOで使う

 DAO/JetやRDOでは、Oracleと接続するのにODBCを使っていた。ODBCの正体は、複数のdllからなるプログラム群で、内部的にはAPIコールにより連携している。このAPIコールによる連携をCOM連携に切り替えるために生まれた技術がADO(ActiveX Data Objects)だ。
 APIからCOMにすることで何があるのかといえば、WindowsがAPIベースからCOMベースに切り替わろうとしているのに合わせて、データアクセス周りもCOM化することにより、OSとの親和性やWindows DNAなどのCOMによる分散環境に統合していこうということになるだろう。
 ADOにもClient(Batch)カーソルとServerカーソルの2種類のカーソル制御が存在するので、それぞれのパケット数を表4にまとめてみた。しかし、残念なことにどちらのカーソルを使ってもMoveNextメソッドの実行でエラーが発生した。いろいろパラメータを変更してみたが、MoveNextメソッド実行時のエラーは解消されなかった。
 この状態で、あえて両者の違いを検証してみれば、MoveNextメソッド実行時に、ClientカーソルだとRDBMSに問い合わせを行なわずにエラーを検出しているが、ServerカーソルだとRDBMSから「ORA-01403:データがありません」という情報を取得してエラーを検出している点だといえるだろう。
 どちらにしても、Recordsetに対するOpenメソッド実行時にレコードの先読みが行なわれており、そこで最終レコードまで読み込んでしまっているとMoveNextメソッドが失敗するのかもしれないが、詳細は不明だ。

表4:ADOのパケット数
  Clientカーソル Serverカーソル
Open(Connection) 44 30
Open(Recordset) 13 12
MoveNext 図21 図22

図21:MoveNext(Clientカーソル)実行時のエラー
図21:MoveNext(Clientカーソル)実行時のエラー

図22:MoveNext(Serverカーソル)実行時のエラー
図22:MoveNext(Serverカーソル)実行時のエラー

OracleをOracle Objects for OLEで使う

 OracleといったらやはりミドルウェアはOracle Objects for OLEを使うべきだろう。RDOやADOでエラーが出たにも関わらず深く追求しなかったのは、大本命が控えている安心感からだ。手元にサードパーティーが販売しているOracle用ODBCドライバやOLE DBプロバイダがあれば、もう少し本腰を入れて調査する気も起きるし、そもそもエラー自体が発生しないだろう。それは、自社製品としてどのインターフェース部分を保証しているかということだ。
 ODBCドライバやOLE DBプロバイダなどのミドルウェアとVisual Basicなどの言語製品側に、メーカー間の技術の切れ目があれば、そこでの不整合はプログラム技術などで回避することができるだろう。しかし、ミドルウェアとRDBMS間に不整合があるときは、どうにも手出しができないという状況になる。ODBCドライバならばOracle製もあると思われるかもしれないが、Oracle8やOracle7の強化点を隠蔽してしまうようなミドルウェアの開発に力を注ぐものだろうか。
 もちろん、このような状況は、ODBCドライバやOLE DBプロバイダのコンセプトが誤っているから発生しているとはいえない。本腰を入れて開発している会社のODBCドライバやOLE DBプロバイダを購入せずに、手元にあるもので済ませようとしていることも原因のひとつだろう。

Oracle Objects for OLEを観る

 Oracle Objects for OLEのメソッドごとのパケット数を表5にまとめてみた。
 今回の注目点は、ReadOnlyではないダイナセットでは、rowidも同時に取得して、このrowidでカレントカーソルを認識しているということだろう(図23)。
 また、Oracle Objects for OLEでもレコードをキャッシュする機能が備わっているので、MoveNextメソッド実行時に必ずしもパケットが流れるとは限らない(図24)。これでは、最新のレコード値が取得できないと思うかもしれないが、Oracleを含めてまともなRDBMS製品では、CreateDynasetメソッドなどによりSQL文に一致するレコード集合を作成した時点でのレコード値が保存されているので、MoveNextメソッド実行時に他のクライアントがどのようなことを行なっているかは気にする必要はない。

表5:Oracle Objects for OLEのパケット数
OpenDatabase 40
CreateDynaset 16
MoveNext  

図23:CreateDynaset実行時のパケット
図23:CreateDynaset実行時のパケット

図24:MoveNext実行時のエラー
図24:MoveNext実行時のエラー

まとめ

 データベースというものをLAN上のパケットを取得することで、その機能や動作などを観てきた。どのようなデータが流れているかがわかれば、ヘルプファイルやいろいろな書籍などに書かれている機能などの違いが少し明確になってきたことと思う。
 冒頭にも書いたが、不思議なもので、データのやりとりがイメージできれば、うまく動作しないときに何に注目して、何を確認しなければいけないかもイメージできるようになってくる。そうなってくれば、障害回避の方法も自然に身に付いてくるだろう。ぜひ、データのやりとりという観点からお手持ちのRDBMS製品を評価してみることをお奨めする。


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