0

BerkeleyDB Java Editionをテストして、プロジェクトで使用できるかどうかを理解しています。

クラスcom.sleepycat.je.Databaseのオブジェクトで動作する非常に単純なプログラムを作成しました。

  • Integer.toString(random.nextInt());のように生成されたキーを使用して、それぞれ5〜15kbのNレコードを書き込みます。

  • これらのレコードを読み取り、作成されたのと同じ順序でメソッドDatabase#getを使用してそれらをフェッチします。

  • メソッドDatabase#getを使用して同じ数のレコードをランダムな順序で読み取ります。

そして今、私は奇妙なことを見ています。3番目のテストの実行時間は、レコード数の増加に伴って非常に非線形に増加します。

  • N = 80000、書き込み= 55秒、シーケンシャルフェッチ= 17秒、ランダムフェッチ=3秒
  • N = 100000、書き込み= 60秒、シーケンシャルフェッチ= 20秒、ランダムフェッチ=7秒
  • N = 120000、書き込み= 68秒、シーケンシャルフェッチ= 27秒、ランダムフェッチ=11秒
  • N = 140000、書き込み= 82秒、順次フェッチ= 32秒、ランダムフェッチ=47秒

(もちろん、テストを数回実行しました。)

私はかなり間違ったことをしていると思います。参照用のソースは次のとおりです(申し訳ありませんが、少し長いです)。メソッドは同じ順序で呼び出されます。

private Environment env;
private Database db;
private Random random = new Random();
private List<String> keys = new ArrayList<String>();
private int seed = 113;


public boolean dbOpen() {
    EnvironmentConfig ec = new EnvironmentConfig();
    DatabaseConfig dc = new DatabaseConfig();
    ec.setAllowCreate(true);
    dc.setAllowCreate(true);
    env = new Environment(new File("mydbenv"), ec);
    db = env.openDatabase(null, "moe", dc);
    return true;
}

public int storeRecords(int i) {
    int j;
    long size = 0;
    DatabaseEntry key = new DatabaseEntry();
    DatabaseEntry val = new DatabaseEntry();

    random.setSeed(seed);

    for (j = 0; j < i; j++) {
        String k = Long.toString(random.nextLong());
        byte[] data = new byte[5000 + random.nextInt(10000)];
        keys.add(k);

        size += data.length;

        random.nextBytes(data);
        key.setData(k.getBytes());
        val.setData(data);
        db.put(null, key, val);
    }

    System.out.println("GENERATED SIZE: " + size);

    return j;
}                   

public int fetchRecords(int i) {
    int j, res;
    DatabaseEntry key = new DatabaseEntry();
    DatabaseEntry val = new DatabaseEntry();

    random.setSeed(seed);
    res = 0;

    for (j = 0; j < i; j++) {
        String k = Long.toString(random.nextLong());
        byte[] data = new byte[5000 + random.nextInt(10000)];
        random.nextBytes(data);
        key.setData(k.getBytes());
        db.get(null, key, val, null);
        if (Arrays.equals(data, val.getData())) {
            res++;
        } else {
            System.err.println("FETCH differs: " + j);
            System.err.println(data.length + " " + val.getData().length);
        }
    }

    return res;
}

public int fetchRandom(int i) {
    DatabaseEntry key = new DatabaseEntry();
    DatabaseEntry val = new DatabaseEntry();

    for (int j = 0; j < i; j++) {
        String k = keys.get(random.nextInt(keys.size()));
        key.setData(k.getBytes());
        db.get(null, key, val, null);
    }

    return i;
}
4

1 に答える 1

1

パフォーマンスの低下は、次の2つの理由で非線形です。

  1. BDB-JEデータ構造はbツリーであり、1つのレコードを取得するためのO(log(n))パフォーマンスを備えています。getメソッドを介してすべてを取得するのはO(n * log(n))です。
  2. 大きなデータセットはRAMに収まらないため、ディスクアクセスはすべての速度を低下させます。ランダムアクセスのキャッシュの局所性は非常に貧弱です。

ある程度の耐久性を放棄することで、書き込みパフォーマンスを向上させることができることに注意してください。ec.setTxnWriteNoSync(true);

また、私が取り組んできたオープンソースのBerkeleyDBの代替品であるTuplを試してみることもできます。まだアルファ段階ですが、SourceForgeで見つけることができます。

BDB-JEとTuplを公平に比較​​するために、キャッシュサイズを500Mに設定し、storeメソッドの最後に明示的なチェックポイントを実行します。

BDB-JEの場合:

  • N = 80000、書き込み= 11.0秒、フェッチ=5.3秒
  • N = 100000、書き込み= 13.6秒、フェッチ=7.0秒
  • N = 120000、書き込み= 16.4秒、フェッチ=29.5秒
  • N = 140000、書き込み= 18.8秒、フェッチ=35.9秒
  • N = 160000、書き込み= 21.5秒、フェッチ=41.3秒
  • N = 180000、書き込み= 23.9秒、フェッチ=46.4秒

Tuplの場合:

  • N = 80000、書き込み= 21.7秒、​​フェッチ=4.4秒
  • N = 100000、書き込み= 27.6秒、フェッチ=6.3秒
  • N = 120000、書き込み= 30.2秒、フェッチ=8.4秒
  • N = 140000、書き込み= 35.4秒、フェッチ=12.2秒
  • N = 160000、書き込み= 39.9秒、フェッチ=17.4秒
  • N = 180000、書き込み= 45.4秒、フェッチ=22.8秒

BDB-JEは、ログベースの形式であるため、エントリの書き込みが高速です。ただし、Tuplは読み取りが高速です。Tuplテストのソースは次のとおりです。

java.ioをインポートします。; java.utilをインポートします。;

importorg.cojen.tupl。*;

public class TuplTest {public static void main(final String [] args)throws Exception {final RandTupl rt = new RandTupl(); rt.dbOpen(args [0]);

    {
        long start = System.currentTimeMillis();
        rt.storeRecords(Integer.parseInt(args[1]));
        long end = System.currentTimeMillis();
        System.out.println("store duration: " + (end - start));
    }

    {
        long start = System.currentTimeMillis();
        rt.fetchRecords(Integer.parseInt(args[1]));
        long end = System.currentTimeMillis();
        System.out.println("fetch duration: " + (end - start));
    }
}

private Database db;
private Index ix;
private Random random = new Random();
private List<String> keys = new ArrayList<String>();
private int seed = 113;

public boolean dbOpen(String home) throws Exception {
    DatabaseConfig config = new DatabaseConfig();
    config.baseFile(new File(home));
    config.durabilityMode(DurabilityMode.NO_FLUSH);
    config.minCacheSize(500000000);
    db = Database.open(config);
    ix = db.openIndex("moe");
    return true;
}

public int storeRecords(int i) throws Exception {
    int j;
    long size = 0;

    random.setSeed(seed);

    for (j = 0; j < i; j++) {
        String k = Long.toString(random.nextLong());
        byte[] data = new byte[5000 + random.nextInt(10000)];
        keys.add(k);

        size += data.length;

        random.nextBytes(data);
        ix.store(null, k.getBytes(), data);
    }

    System.out.println("GENERATED SIZE: " + size);

    db.checkpoint();
    return j;
}

public int fetchRecords(int i) throws Exception {
    int j, res;

    random.setSeed(seed);
    res = 0;

    for (j = 0; j < i; j++) {
        String k = Long.toString(random.nextLong());
        byte[] data = new byte[5000 + random.nextInt(10000)];
        random.nextBytes(data);
        byte[] val = ix.load(null, k.getBytes());
        if (Arrays.equals(data, val)) {
            res++;
        } else {
            System.err.println("FETCH differs: " + j);
            System.err.println(data.length + " " + val.length);
        }
    }

    return res;
}

public int fetchRandom(int i) throws Exception {
    for (int j = 0; j < i; j++) {
        String k = keys.get(random.nextInt(keys.size()));
        ix.load(null, k.getBytes());
    }

    return i;
}

}

于 2012-07-08T02:50:35.513 に答える