2011年2月24日木曜日

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

Apache Derbyに大量データをinsertしてみました。
Derbyには組み込みモードとサーバモードがありますが、組み込みモードでのみ確認しました。

Derbyを動かすまでの手順は以下の通り。基本的にはマニュアル通りです。
・Derby10.7.1.1をダウンロードする(現時点での最新)
・DERBY_HOMEを設定する
・$DERBY_HOME/binをPATHに追加
・$DERBY_HOME/lib/derby.jarをCLASSPATHに追加

・ijを実行し、testdbにConnectする
[user@user bin]$ ij
ij バージョン 10.7
ij> CONNECT 'jdbc:derby:testdb;create=true';

・hashテーブルの作成
ij> create table hash ( id integer PRIMARY KEY , value varchar(40));
0 行が挿入/更新/削除されました

下準備はこれで完了です。

毎回同様ですが、100万件のCSVネタを読み込みながらinsertを100万回行います。
以下、赤字が変更点です。
import java.sql.*;
import java.io.*;
import java.util.Date.*;

public class derbyins {
    public static void main (String args[]) {
        Connection db = null;
        PreparedStatement ps = null;
        String sql = "insert into hash values(?,?)";
        String url = "jdbc:derby:testdb";
        BufferedReader br = null;
        int i = 0;
        try {
            Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
            db = DriverManager.getConnection(url);
            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);
    }
 }

100万行insertするのに227sかかりました。SQLite3+JDBCよりもずいぶん遅く、PostgreSQL+JDBCよりも遅い結果となりました。

ApacheDerbyというものは今回初めて知ってさらっと使ってみましたが、非常に手軽に使えるのは間違いありません。Derbyのメリットをあげると以下でしょうか。
・JDBCの品質が高い(はず)
・組み込みモードとサーバモードの2種類で使える
・レプリケーションが標準で搭載されている

しかし、残念ながら日本ではDerbyを使っているという話は少なくともネット上には見受けられません。これは個人的には以下のような理由かなと思います。
・PublicDomainでは無い→Sqliteの方が使用のハードルが低い
・Sqliteの知名度に勝てない
・Javaでしか使えない
・さして高速でも無い

まあ、組み込みとサーバモード両方で使えたり、レプリケーション出来たりしても、私には使う場所が無いですね。全然Sqliteでいいです。

2011年2月17日木曜日

JavaでSqlite3に大量データをinsertしてみた

今回はJavaからsqlite3に大量データをinsertしてみました。
以前と同じですが、条件は再掲します。

まず、sqlite3でテーブルを作ります。
sqlite> CREATE TABLE hash ( id INTEGER PRIMARY KEY , value TEXT );

insertするネタはcsvファイルで
1,356a192b7913b04c54574d18c28d46e6395428ab
2,da4b9237bacccdf19c0760cab7aec4a8359010b0
3,77de68daecd823babbb58edb1c8e14d7106e83bb

1列目は数字で2列目は数字のsha1値です。
これを100万行分用意します。(neta.csv)

次にsqlite3のJDBCを探します。複数ありそうですが、今回はココにあったやつをダウンロードしました。HP上の記載を見るとsqliteは3.6.14がベースとの事です。

次に以前作成したpostgresqlへのinsertするjavaアプリを適度にsqlite用に数行修正しました。変更点は以下、赤字です。

import java.sql.*;
import java.io.*;
import java.util.Date.*;

public class sqliteins {
    public static void main (String args[]) {
        Connection db = null;
        PreparedStatement ps = null;
        String sql = "insert into hash values(?,?)";
        String url = "jdbc:sqlite:testdb";
        BufferedReader br = null;
        int i = 0;
        try {
            Class.forName("org.sqlite.JDBC");
            db = DriverManager.getConnection(url);
            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);
    }
 }

CLASSPATHを通して実行します。
100万件のinsertの実行時間は39sでした。
因みに、
commitを10万回に1回にした場合→21s
commitを50万回に1回にした場合→19s
とさらに早くなりました。

全く同じコードでもPostgreSQLよりも断然早いです。そもそもPostgreSQLやその他DBMSとSqliteは用途が若干異なる為、比較する意味はあまり無いかもしれませんが、Sqliteはかなりいい感じ。。。ですね。

2011年2月8日火曜日

JavaでPostgreSQLに大量データをinsertしてみた

JAVAからPostgreSQLに例によって大量データをINSERTしてみました。
環境は以下です。
・Fedora13+PostgreSQL9.0 + JDBCも9.0(Type4)+JAVA6
以下のようなコードを作成しました。見苦しいところはお許しを。。

import java.sql.*;
import java.io.*;
import java.util.Date.*;
public class postgresqlins {
public static void main (String args[]) {
            Connection db = null;
            PreparedStatement ps = null; 
            String sql = "insert into hash values(?,?)";
            String url = "jdbc:postgresql:testdb";
            String usr = "postgres";
            String pwd = "postgres";
            BufferedReader br = null;
            int i = 0;
            try {
               Class.forName("org.postgresql.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);
      }
}

以前と同様にneta.csvという100万件のデータを読み込んで、PostgreSQLにINSERTしています。INSERTにかかった時間は130sでした。
以下は感想。
・JDBCはやっぱり安定している。(Pythonと違って戸惑う事が無し!)
・Pythonのドライバと比較すると、約10倍速い。
・この差は果たして、言語的なものなのか、ドライバの優劣なのか、アプリがおかしいのか?は不明でした。
・ps = db.prepareStatement(sql) のコードをwhileループの中に書くと倍以上遅くなる。構文解析(PARSE)処理が多発するからでしょう。
・Commitタイミングを10万件にしてやってみたが、大差は無かった。