2011年3月5日土曜日

H2に大量データをinsertしてみた

H2 databaseというDBで大量データinsertをやってみました。
H2のホームページを見ているとDerbyよりも高機能/高速である事を売りにしています。

H2にはDerbyと同様に組込モードとサーバモードの両方が実装されていますが、以下の確認は組込モードのみで実施おり、バージョンは1.3.152です。順序は以下のとおりです。
・H2のページからダウンロード
・CLASSPATHを設定
・ java -cp h2*.jar org.h2.tools.Shell を実行する
(もしくは、 java -cp h2*.jar org.h2.tools.Server)
・コマンドラインからテーブルの作成を実施する
create table hash ( id integer PRIMARY KEY , value varchar(40));
・insert用のCSVネタを準備する
・以下のアプリを実行する
(赤字が修正した箇所です)

import java.sql.*;
import java.io.*;
import java.util.Date.*;
public class H2ins {
        public static void main (String args[]) {
                Connection db = null;
                PreparedStatement ps = null;
                String sql = "insert into hash values(?,?)";
                String url = "jdbc:h2:testdb";
                String usr = "sa";
                String pwd = "";
                BufferedReader br = null;
                int i = 0;
                try {
                        Class.forName("org.h2.Driver");
                        db = DriverManager.getConnection(url,usr,pwd);
                        db.setAutoCommit(false);
                        ps = db.prepareStatement(sql);
                } catch (Exception ex) {
                        ex.printStackTrace();
                }
                java.util.Date d1 = new java.util.Date();
                System.out.println(d1);
                try{
                        br = new BufferedReader(new InputStreamReader(new FileInputStream("neta.csv")));
                        String line;
                        while( (line = br.readLine()) != null ){
                                i++;
                                String[] col = line.split(",");
                                int id = new Integer(col[0]);
                                String value = col[1];
                                ps.setInt(1,id);
                                ps.setString(2,value);
                                ps.executeUpdate();
                                if( i % 10000 == 0) {
                                        System.out.println(i);
                                        db.commit();
                                }
                        }
                        // データベース切断
                        db.commit();
                        ps.close();
                        db.close();
                        br.close();
                } catch (Exception ex) {
                        ex.printStackTrace();
                }
                java.util.Date d2 = new java.util.Date();
                System.out.println(d2);
        }
 }

やってみると約20sで100万件のinsertが完了します。高速だと言う謳い文句は間違っていないようです。

またH2はSqliteを意識しているようで、manual上のAndroidでの実装の箇所でSqliteでは無くH2を使う理由として以下を挙げています。(抜粋)
・参照制約+チェック制約
・豊富なデータTypeとSQL
・他DBMSの互換モード
・完全なUnicodeのサポート
・ユーザ定義関数+トリガー
・全文検索機能
・複数コネクションの許容
・データベースの暗号化

Sqliteの最新では全文検索機能等は存在しているんで、あくまでAndroidでのSqlite実装が古いバージョンで行われているという事なんでしょうか。。しかし、組込モードで複数コネクションの許容とかしてもしょうがないんじゃないかなーー。

何点か補足します。

・ Derbyでも気になりましたが、DBにConnectするタイミングで若干のタイムラグを感じます。何らかの初期処理(Classのロードとか)で時間がかかっているんでしょうかね。尚、insert時間の測定は純粋にinsertの時間のみを測っている為、Connect/Disconnectの時間は含んでいません。

・java -cp h2*.jar org.h2.tools.Shellで最初にDBの接続情報を入力しますが、Useridが自動的に"sa"となります。
(ShellからUserid/Password無にする方法が分かりませんでした)
java -cp h2*.jar org.h2.tools.Server ではuserid/passwordを無として設定できました。