gpt4 book ai didi

java - BerkeleyDB JE 随机访问时间非线性增加

转载 作者:行者123 更新时间:2023-12-01 15:19:52 27 4
gpt4 key购买 nike

我正在测试 BerkeleyDB Java 版,以了解我是否可以在我的项目中使用它。

我创建了非常简单的程序,它与 com.sleepycat.je.Database 类的对象一起使用:

  • 写入 N 条记录,每条记录 5-15kb,生成的键类似于 Integer.toString(random.nextInt());

  • 读取这些记录,并按照创建的顺序使用 Database#get 方法获取它们;

  • 使用 Database#get 方法以随机顺序读取相同数量的记录。

我现在看到了奇怪的事情。第三个测试的执行时间随着记录数量的增加呈非线性增长。

  • 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;
}

最佳答案

性能下降是非线性的,原因有两个:

  1. BDB-JE 数据结构是一个 B 树,检索一条记录的性能为 O(log(n))。通过 get 方法检索所有内容的时间复杂度为 O(n*log(n))。
  2. RAM 无法容纳大型数据集,因此磁盘访问会降低速度。随机访问的缓存局部性非常差。

请注意,您可以通过放弃一些持久性来提高写入性能:ec.setTxnWriteNoSync(true);

您可能还想尝试 Tupl,这是我一直在研究的开源 BerkeleyDB 替代品。它仍处于 alpha 阶段,但您可以在 SourceForge 上找到它。

为了公平比较 BDB-JE 和 Tupl,我将缓存大小设置为 500M,并在存储方法末尾执行显式检查点。

使用 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.;

导入 org.cojen.tupl.*;

公共(public)类TuplTest { 公共(public)静态无效主(最终字符串[] args)抛出异常{ 最终 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;
}

}

关于java - BerkeleyDB JE 随机访问时间非线性增加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11098085/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com