Delphiで組み込みFirebirdサンプル
準備
組み込みのFirebird Embedded ServerをDelphiから利用して簡単な住所・郵便番号検索データベースを作成したいと思います。
- 開発環境:Boland Delph7 Professional(Inter Base、DBコンポーネントが使える環境)
- 日本郵便からお好きな郵便番号データをダウンロードして下さい。
Firebird Embedded Server組み込み方法
※サンプルではすでに組み込まれています。
- Firebird日本ユーザー会ダウンロードページからリンクをとんでFirebird-xxxxxxxx_embed.zipをダウンロードして解凍してください。(私は2.0.4を使用しました。)
- 解凍したら、fbembed.dllのファイル名をgds32.dllに変更します。
- 解凍フォルダ内の以下のファイルをアプリケーションフォルダに配置します。
アプリケーション.exe gds32.dll ← fbembed.dllのファイル名を変更したもの ib_util.dll icudt30.dll icuin30.dll icuuc30.dll firebird.conf firebird.msg intl/ fbintl.dll fbintl.conf udf/ fbudf.dll
詳しくはFirebird日本ユーザー会にReadmeを日本語訳したREADME_embedded_JP.txtがあります。
Firebird Embedded Serverポイント
- 簡単な手順で組み込める。
- 高機能(ドメイン、ストアドプロシジャ、他機能豊富)でありながら、結構高速。
- Firebird Embedded Serverは一つのプロセスからしか接続することが出来ません。なので複数アプリから同じデータベースを利用する場合には向いていません。
- Firebird Embedded Serverはリモートで接続することが出来ません。なので「servername:d:test.fdb」「192.168.0.2:d:test.fdb」とかでの接続は×。
サンプルソース
作成フォーム
実行フォーム
入力欄に住所の一部を入力すると、DB内から文字列が含まれている住所をインクリメンタルサーチします。
ソース
データベースはアプリフォルダ内のPOST.FDBに接続しています。DBファイルはGUI管理ツールなどで作成し、POST_TABLEテーブルを作成しPOST_CODE,ADDRESSフィールドを追加しています。
レコードをINSERTする方法は3種類表記しました。速度も見れるようにしたのでコメントアウトしたり外したりして他の方法もお試し下さい。(※作者未熟のため他にもっと速いINSERT方法があるかもしれません。よろしかったら掲示板等で教えて頂けるとうれしいです。)
クエリはTIBTableのFilterを使用した方が簡単なので、Filterを使ってクエリしています。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IBDatabase, DB, IBCustomDataSet, IBTable, StdCtrls, Grids,
DBGrids, ExtCtrls, Menus, DBCtrls, IBQuery, ComCtrls;
type
TForm1 = class(TForm)
IBTable1: TIBTable;
IBDatabase1: TIBDatabase;
IBTransaction1: TIBTransaction;
DataSource1: TDataSource;
Panel1: TPanel;
DBGrid1: TDBGrid;
MainMenu1: TMainMenu;
File1: TMenuItem;
Open1: TMenuItem;
Exit1: TMenuItem;
N1: TMenuItem;
OpenDialog1: TOpenDialog;
IBTable1POST_CODE: TIBStringField;
IBTable1ADDRESS: TIBStringField;
Splitter1: TSplitter;
LabeledEdit1: TLabeledEdit;
DBNavigator1: TDBNavigator;
Memo1: TMemo;
IBQuery1: TIBQuery;
ProgressBar1: TProgressBar;
N2: TMenuItem;
Label1: TLabel;
procedure Exit1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Open1Click(Sender: TObject);
procedure N2Click(Sender: TObject);
procedure LabeledEdit1Change(Sender: TObject);
private
{ Private 宣言 }
procedure ClearTable;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//テーブルの全レコードを削除
procedure TForm1.ClearTable;
begin
IBQuery1.SQL.Text := 'DELETE FROM POST_TABLE';
IBQuery1.ExecSQL;
end;
procedure TForm1.Exit1Click(Sender: TObject);
begin
Close;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
IBTable1.Open;
end;
//郵便番号データのインポート
procedure TForm1.Open1Click(Sender: TObject);
var DataList, RecList: TStringList; i, Count: Integer;
postcode, address: string; StartTime: Cardinal;
begin
OpenDialog1.InitialDir := ExtractFileDir(Application.ExeName);
if OpenDialog1.Execute then begin
DataList := TStringList.Create; //郵便番号データリスト
RecList := TStringList.Create; //郵便番号レコードリスト
DBGrid1.Columns.BeginUpdate;
DBNavigator1.Hide;
try
try
ClearTable;
DataList.LoadFromFile(OpenDialog1.FileName);
Count := DataList.Count;
ProgressBar1.Max := Count;
StartTime := GetTickCount; //INSERT前開始タイムを取得
for i := 0 to Count-1 do begin
RecList.CommaText := DataList[i];
with IBTable1 do begin
//郵便番号(7桁)
postcode := RecList[2];
//都道府県名 + 市区町村名 + 町域名
address := RecList[6] + RecList[7] + RecList[8];
//INSERT方法3種、作者の環境では速さは 1<2<3 です。
{INSERT方法1}
// Insert;
// FieldByName('POST_CODE').AsString := postcode;
// FieldByName('ADDRESS').AsString := address;
// Post;
{INSERT方法2}
// InsertRecord([postcode, address]);
{INSERT方法3}
with IBQuery1 do begin
SQL.Text := 'INSERT INTO POST_TABLE VALUES (''' +
postcode + ''', ''' + address + '''); ';
ExecSQL;
end;
ProgressBar1.StepIt;
end;
end;
IBTransaction1.Commit;
Memo1.Lines.Add('');
Memo1.Lines.Add(ExtractFileName(OpenDialog1.FileName) + 'のインポート');
Memo1.Lines.Add('INSERT数 = ' + IntToStr(Count));
Memo1.Lines.Add('総INSERT時間 = ' +
IntToStr(GetTickCount - StartTime) + 'ms');
Memo1.Lines.Add('');
except
IBTransaction1.Rollback;
end;
finally
IBTable1.Close;
IBTable1.Open;
DBNavigator1.Show;
DBGrid1.Columns.EndUpdate;
ProgressBar1.Position := 0;
DataList.Free;
RecList.Free;
end;
end;
end;
procedure TForm1.N2Click(Sender: TObject);
begin
ClearTable;
IBTransaction1.Commit;
IBTable1.Close;
IBTable1.Open;
end;
//住所のクエリ
procedure TForm1.LabeledEdit1Change(Sender: TObject);
var StartTime: Cardinal;
begin
StartTime := GetTickCount;
with IBTable1 do begin
Filter := 'ADDRESS LIKE ''%' + LabeledEdit1.Text + '%''';
Close; Open;
end;
Memo1.Lines.Add('クエリ時間 = ' +
IntToStr(GetTickCount - StartTime) + 'ms');
end;
end.
速度
上のソースを元に以下の環境でインサートとクエリ速度を測ってみました。
実行環境
CPU: Intel Core 2 Duo E6600 (Conroe-4M, B2)
2400 MHz (9.00x266.7) @ 2383 MHz (9.00x264.8)
Memory: 2048 MBytes @ 331 MHz
Graphics: Intel 82945G Integrated Graphics Controller [AsusTek]
Intel GMA950, 128 MB
OS: Microsoft Windows XP Professional Build 2600
同じ動作を3回ずつ計測します。
INSERT処理 東京都の全郵便番号データ(3580件)をINSERT 総INSERT時間 = 2500ms 総INSERT時間 = 2625ms 総INSERT時間 = 2703ms 全国の全郵便番号データ(122635件)をINSERT 総INSERT時間 = 95031ms 総INSERT時間 = 95516ms 総INSERT時間 = 99188ms
クエリ 東京都の全郵便番号データ(3580件)の住所から「亀有」を含むものを抽出 クエリ時間 = 15ms クエリ時間 = 16ms クエリ時間 = 16ms 全国の全郵便番号データ(122635件)の住所から「亀有」を含むものを抽出 クエリ時間 = 297ms クエリ時間 = 313ms クエリ時間 = 313ms※郵便番号データは2009/2のもの。
※最速のコーディング方法ではなく、一般的と思われるコーディング方法で試しました。
