FireBird DBMS を使う
[ Prev 2. データベースを作る ] [ Top 目次 ] [ Next 4. 検索パターンとその実装 ]

3. プログラミング言語

3.1. C それとも Perl ……?

FireBird/InterBase には gpre という gcc のプリプロセッサがあり、C言語から直接操作することができます。
私が、InterBase3.0 時代から InterBase/FireBirdを愛用してきているのも、この強力で万能な gpre があることが大きな理由の一つでもあります。

そのほかに、Perl,Python,java,PHP など多くの言語がサポートされているようです。

あ、もちろん Delphi, C++Builder などの Borland製品もあります。

Python と java は、勉強不足で、よく知りません。
PHP はどうも気持ち悪いです。

じつは、とんでもないことに!今まで個人的には CGI プログラムは C で書くことが多かったのです。
なんというスリリングなバッファオーバーフローの恐怖との闘いの世界!

今回は常識的に Perl でやってみました。

3.2. IBPerl

3.2.1. IBPerl について

IBPerl という、Module があります。
作者は、Bill Karwin 氏で、GPL ライセンスです。

Red Hat 9 上での makeでは若干のパッチが必要でした。

IBPerl.pm のソースを読むと、3個のオブジェクトしかありません。
これだけで、一通りのことはできます。

そんだけ。なんて分かりやすい!

3.2.2. オブジェクト Connection の簡単なリファレンス

IBPerl::Connection
    method
        new()         データベース接続
        create()      データベースの新規作成
        disconnect()  データベース切断 
    parameter
        Server        サーバ名(デフォルトはlocalhost)
        Path          データベースのPath
        Protocol      TCP/IP(デフォルト), NetBEUI, IPX/SPX
        User          ユーザー名(省略されると環境変数 ISC_USER)
        Password      パスワード(省略されると環境変数 ISC_PASSWORD)
        Dialect       1(デフォルト)または3
        Charset       NONE(デフォルト),EUCJ_0208,SJIS_0208
        Role          NONE(デフォルト)
    Return: データベースハンドル
SAMPLE:
my($DB)=IBPerl::Connection->new(Server=>"hostname.domain.tld",
                                Path=>"/DB/birds/birds.fdb",
                                User=>"SYSDBA",
                                Password=>"##########");

3.2.3. オブジェクト Transaction の簡単なリファレンス

IBPerl::Transaction
    method
        new()        トランザクション開始
        commit()     コミット
        rollback()   ロールバック
    parameter
        DataBase     データベースハンドル
        Active       (ReadOnly Property)トランザクションの状態
    return           トランザクションハンドル
SAMPLE:
my($trans)=IBPerl::Transaction->new($DB)

3.2.4. オブジェクト Statement の簡単なリファレンス

IBPerl::Statement
    method:
        new()            オブジェクト生成
        execute()        SQL実行
        fetch(<line-no>) フェッチ(行番号の指定も可能)
        rollbacl()       rollback
    parameter:
        Transaction      トランザクションハンドル
        SQL              SQL文
        TimeStampFormat  TIMESTAMP型のフォーマット(strftime(3)形式)
        DateFormat       DATE型のフォーマット     (strftime(3)形式)
        TimeFormat       TIME型のフォーマット     (strftime(3)形式 dialect3)
    return               ステートメントハンドル
SAMPLE:
mt($state)=IBPerl::Statement->new(Transaction=>$trans,
                                  SQL=>"SELECT * FROM ORDERTAB");
if ($state->execute()==0){
    my(%hash);
    while ($state->fetch(\%hash)==0){
        for (keys %hash){
            print("$_=$hash{$_}\n");
        }
    }
}

3.3. とりあえず書いてみる

何はともあれ動かしてみよう。

ともかくデータがないことには始まりません。
ってわけで、1.3.項のデータをデータベースに放り込むプログラムを書いてみました。

3.3.1. データ流し込みプログラム

このプログラムを実行してみると、SQL*Loader (c) Oracle のようなものが不要な訳が分かると思います。

データ更新部分は、52,56,57 行の 3ステップです。

4 個のテーブルに対して、40,000 回の存在チェックとINSERT、同時に 1 個のテーブルに対してトリガーによる参照と更新、そして 23 個の INDEX の同時更新を『オンライン状態のまま』行っています。
実験環境の古いマシンで 14 秒なので、今どきの PC サーバなら数秒(1 桁)でしょう。

参考までに、このプログラムの最後の commit を rollback に変えて、rollback 処理のみの所要時間を計測したところ、約 0.3 秒でした。 FireBird の特徴がよく分かります。

2章の最後の PROCEDURE PSGO_CHKINSERT を使っています。

さくっと、動きました。

3.3.2. (参考) C 版

Perl で十分に速いのですが、試しに gcc/gpre で書いてみたら約 4 秒 ( 2,500明細/秒 ) でした。
3.5 倍の速度差。思った以上に差が開きました。
( オンライン状態での更新でこの速度は、他の DBMS に大きく水を空けているかもしれない。 )

IBPerl のストアードプロシジャ呼び出しのオーバーヘッドはやはり大きいようです。
どうしても速度が欲しい時は C の出番になるかもしれません。

ただし、gpre はこのような更新系の場合は文句なしに速いのですが、SUSPEND 付の PROCEDURE を呼び出す参照の場合に限り、強制的に TCP_NODELAY ( tinygram 回避のための tcp/ip Nagle アルゴリズムを使用しないモード ) になるように見えます。

これは一長一短で、使用環境を考えないと逆効果になります。

この件に関して日本語の情報は皆無、英語の情報も不十分で、詳しくはソースを追ってみるしかなさそうですが、やりきれていません。

3.3.3. 検証

isql で中身を見ます。OK!

SQL> SELECT * FROM COUNTERTAB;
TABLENAME                COUNTMAX
==================== ============
ORDERTAB                       23
FAMILY                        146
GENUS                        2060
SPECIES                      9946
SQL> SELECT COUNT(*) FROM ORDERTAB;
       COUNT
============
          23
SQL> SELECT COUNT(*) FROM FAMILY;
       COUNT
============
         146
SQL> SELECT COUNT(*) FROM GENUS;
       COUNT
============
        2060
SQL> SELECT COUNT(*) FROM SPECIES;
       COUNT
============
        9946
SQL> SELECT ORDERJPN,FAMILYJPN,SPECIESJPN FROM VSPECFULL WHERE FAMILYNAME='Gaviidae';
ORDERJPN                 FAMILYJPN                                SPECIESJPN
======================== ======================================== ========================================
コウノトリ目             アビ科                                   アビ
コウノトリ目             アビ科                                   オオハム
コウノトリ目             アビ科                                   シロエリオオハム
コウノトリ目             アビ科                                   ハシグロアビ
コウノトリ目             アビ科                                   ハシジロアビ

3.4. さまざまな DB 操作

使えることが分かったので、本格的に使う準備です。

3.4.1. サブルーチン

よく使うDB操作をサブルーチン化してみました。

3.4.2. パッケージ

これらサブルーチンをPackageにしました。

[ Prev 2. データベースを作る ] [ Top 目次 ] [ Next 4. 検索パターンとその実装 ]
written by © 2009,OOSATO,Kazzrou : kazz_atmark_kk.iij4u.or.jp

この HTML を検査する。 ( XHTML 1.0 Strict で書かれています )
Another HTML Lint Gateway ( Mirrored by htmllint.oosato.org )