在Berkeley DB Java版中实现SQL查询
前言
众所周知,Berkeley DB 产品家族(包括了 C语言版,Java版和XML数据库)是一套高效率的,可扩展的嵌入式数据库引擎。此处,所谓数据库引擎是指它提供了除SQL处理层以外的所有关系数据库的功能(如事务性(ACID)支持,数据存储,数据恢复等)。那么,您不禁要问,为什么Berkeley DB产品不提供对SQL的支持呢?答案很简单,它可以嵌入到您的应用代码中,在应用代码的地址空间运行,从而达到高效率。
到底有多高效?
在我自己的DELL OptiPlex 745 台式机上(Intel(R) Core(TM)2 CPU 6400, 2G memory, running Ubuntu 7.04 Server x86_64),用自己写的一个单线程的例子程序在9秒内读取了100万条记录,22秒内插入100万的记录。
从关系表的角度看,我插入数据的行定义,大致如下:
f0 INT PRIMARY KEY, f1 STRING PRIMARY KEY, id LONG, one STRING, two DOUBLE, three STRING, zip INT, city STRING, state STRING
在Berkeley DB Java 版中的定义如下:
@Persistent
class CompositeKey {
@KeyField(1)
int f0 = 0;
@KeyField(2)
String f1 = "The quick brown fox jumps over the lazy dog.";
CompositeKey() { } // for bindings
CompositeKey(int f0) {
this.f0 = f0;
}
CompositeKey(int f0, String f1) {
this.f0 = f0;
this.f1 = f1;
}
@Override
public String toString() {
return "CompositeKey: (" + f0 + "," + f1 + ")";
}
}
@Entity
class BasicEntity {
@PrimaryKey
CompositeKey key;
protected long id = 0;
protected String one = "one";
protected double two = .2d;
protected String three = "three";
Address address = new Address();
BasicEntity() { }
BasicEntity(int i) {
this.key = new CompositeKey(i);
}
public void modify() {
id++;
one += "1";
two = id;
three += "3";
address = new Address("Shenzhen", "Guangdong, China", 500001);
}
@Override
public String toString() {
return "BasicEntity: (" + key + "," + id + "," + one + "," +
two + "," + three + ", " + address + ")";
}
}
@Persistent
class Address {
private String city = "Boston";
private String state = "Massachusetts";
private int zip = 10001;
Address() { }
Address(String city, String state, int zip) {
this.city = city;
this.state = state;
this.zip = zip;
}
@Override
public String toString() {
return "Address: (" + city + "," + state + "," + zip + ")";
}
}
如何实现SQL查询
对于现在做JAVA企业应用的,他们很多都熟悉SQL语句。于是不禁要问:我想利用Berkeley DB Java版的高效,轻量级的类库,达到和关系数据库一样的功用,如何实现?也就意味着,我要自己写SQL解析器,支持SQL查询,插入,更改和删除操作,该怎么写呢?会不会很麻烦?
我的白皮书《Performing Queries in Oracle Berkeley DB Java Edition》里详细论述了,如何利用Berkeley DB Java版的直接持久层(也就是一套基于Berkeley DB Java版的底层接口和JDK5 Annotations 的拓展,英文简称叫DPL),实现了如下的SQL查询:
- SELECT * FROM tab ORDER BY col ASC;
- SELECT * FROM tab WHERE col LIKE ‘prefix%’;
- SELECT * FROM tab WHERE col >= A AND col <= B;
- SELECT * FROM tab WHERE col1 = A AND col2 = B;
- SELECT t1.* FROM table1 t1, table2 t2 WHERE t1.col1 = t2.col1 AND t2.col2 = A;
当然,阅读以后您会发现,在SQL查询的代码里稍做修改就变成了SQL更新/删除的操作。最后,恭喜您,现在您知道如何写一个最基本的SQL解释器了,不是吗?:-)
BDB JE 不错,已经被我在网站开发中使用了。使用了DPL。谢谢!。:-)
@Anderson Mao
聪明!据我所知,目前国内能用好BDB JE的案例不多。你是怎么用的?用的怎么样?不妨简单说说,分享一下你的经验,或者一起探讨一下。
我看了那个书之后,讲的都是sql的查询啊,
怎么来实现删除和修改哦???
请指点一下。谢谢!
@徐明松
DPL的curosr(如EntityCursor)除了提供get方法,还提供了delete和update方法。如果是做查询,选择get;更新和删除选择update/delete。具体请参考直接持久层的Javadoc: http://www.oracle.com/technology/documentation/berkeley-db/je/java/com/sleepycat/persist/package-frame.html。
谢谢……非常谢谢
@chaohuang
这个网址打不开 能给个详细连接吗
我曾经使用bdb做过网页抽取技术的研究,算是蛮成功的,但是如果数据库除了问题,怎么去恢复它,这个问题困扰了很久
@wangyazhen
点击JE的Javadoc地址。打开后,选择com.sleepycat.persist包。
恢复有很多策略,如果你带着具体问题来问会好些。我建议你带着问题去JE的论坛提问-网址见右侧边栏的“常用链接”。
高手们好:
我用BDB-JE写入16W数据,然后重起电脑,在进行查询,查询100条,第一次速度为1秒多,那么我在查1W多次就能达到500毫秒吧,不知道您是怎么写的会这么快,我设置了Cache为2个G,但是我查看了每次读数据缓存命中为0,不知道是怎么回事,高手能指点一下吗谢谢了,这是我的QQ375391019和邮箱:sanzang_xulong@126.com 请那位好心高手指教一下谢谢了,我弄好一个多星期了速度就是上不好,郁闷死了!
@三葳
首先,我觉得你程序测试的是硬盘IO的速率,而非JE的性能。理由是,你是电脑重起后进行查询的(cache是冷的;并且你程序preload数据大小的值很低,才10M),因而NCacheMiss很高,很多时间耗费在IO wait上。
我们在笔记本(Windows, 5400rpm 硬盘)和台式机(Linux, 7200rpm 硬盘)上的测试结果也印证我的观点。我们建议你:
* 首先,建议用JE的DPL,而不是base API。
* 你可以试试在Linux下面运行你的程序(降低I/O的额外开销),如果有可能,配置7200rpm或更高的硬盘。
* 你把JVM的大小尽可能设大一点(例如java -Xmx1024M),然后preload的大小尽可能地调高(如preload 300M),这样的目的是将nCacheMiss降到最低。
采用如上3点建议,我们在台式机上用你程序的测试耗时约在50 ms (-Xmx1024M, 默认的cache设置, preload 所有数据, 100次随机读耗时50ms)。
文档都不能下了! 网上也找不到 想用BDB还真挺难,能不能提供点资料,发送:yubaojian0616@163.com
谢谢!
请问 BDB怎么实现in查询 这对于我们用的lucene+SQL in 组合很有用,怎么提高它的性能! 数据大概80G 大约 600+万条
@于堡舰
OTN 更新了文档链接,新的地址为: http://www.oracle.com/technetwork/database/berkeleydb/performing.pdf
如果实现in查询,你需要遍历所有记录,逐条判断是否符合条件。
你考虑购买BDB的license吗?你可以给我发邮件:chao.huang [at] oracle.com。 Oracle会阻止163/263等邮件,所以推荐使用gmail/hotmail/yahoo mail。
@chaohuang 请问java版怎么实现sql查询 比如select * from table where A=? and B=? and c<? order by D 我看了好久了 没有找到答案 希望得到帮助
@adsl
你可以参考我的那篇文章:
1. 得到SELECT * FROM tab where A=? and B=?的结果(假设是一个集合或者一个游标),然后针对该集合或者游标做“c<”和”order by D”。
2. 或者,先得到SELECT * FROM tab where c<的结果(假设是一个集合或者一个游标),然后针对该集合或者游标做“A=? and B=?”和”order by D”。
选译#1或者#2关键看中间结果集的大小,即集合或者游标的结果集的大小。返回的中间结果集越小,后续处理越高效。