ODBCでプログラミングをしたことがなくて、ODBCが遅いと勘違いしている人たちにお読みいただき記事です。一気に書くと長くなるので分割して掲載します。
ODBCでこてこてにプログラミングしたことのない人は、一度Inside ODBCをよく読んで見るべきだと思います。
私もかつては「ODBCは遅い」と勘違いしていた人間の一人でした。しかしながら、今から8年ほど前に考えがガラッと変わりました。当時はODBC2.xの時代でした。「使い方を誤れば、ODBCはとんでもなく遅い、しかし、使い方を正しくすれば、高速にアクセスできる」、この事実を自分自身が実証したことが大きな理由です。当時、私は、某メーカのオブジェクト指向開発ツール(コンパイラ)のサポートならびにコンサルティングを担当していました。顧客からのクレームが発端でした。「バッチ処理が2週間たっても終了しない!どうにかなりませんか!!」そのバッチ処理は、その開発ツールが提供していたODBC用アクセスのクラスを利用して実装されていました。バックエンドデータベースは、Sybase SQL Anywareでした。メインフレームからダウンロードしてきた巨大な初期データを新規システムにインポートするための処理が2週間以上かかるのは配置上・運用上、致命的な問題です。この問題に対して、私は基本からODBCを学び、Inside ODBCにいたっては原書と日本語版と両方を通読しました。目からうろこでした。
最初のポイントは、フェッチしたデータをどうやって取得するか、その手法に大きく依存します。ODBCでは、クエリーした結果を取得するのに2つの方法があります。
・SQLGetData()を使う方法
・SQLBindCol()を使う方法
問題となっていたODBCアクセス用のクラスは調査したところ、SQLGetData()を利用していました。このAPIがデータを取得する際のボトルネックでした。メタデータなしに実行時に(ある意味ルーズに)データを取ってこれる反面、関数の呼び出し回数が増えます。一方、SQLBindCol()を使う方法は、事前に取ってくる列のメタ情報が必要で、メモリ空間へのマップが必要です。しかしながら、フェッチを実行した瞬間に確保したメモリ領域に列データが格納されることにより、SQLGetData()を繰り返し呼び出すという悪夢から開放され、ODBCマネージャへの呼び出し回数は激減します。実際にプロファイリングを実行し、SQLGetData()によるオーバヘッドであることを顧客に提示し、私は、新たなODBCアクセス用のクラスの実装を約束しました。この時の最重要事項な意思決定は、顧客がすでに実装済みのコードは一切書き換えず、等価なデータアクセスクラスを提供するということでした。
ここからは、メタデータとの闘いでした。SQLGetData()はメタデータがなくてもデータが取得できます。SQLBindCol()はメタデータなしには実行できません。続いて顧客に提案したのは、コードジェネレータによるクラスの生成でした。もちろん、ジェネレータそのものと基本クラスについては私が実装するという条件で。これには顧客は喜んで合意してくださいました。
ここまでで、クエリーから結果セットを取ってくるまでのプロセスは改善できました。
しかし、闘いはこれからであったことを即座に思い知らされることに。
続きは、次回へ。