Oracle Berkeley DB 支持SQL啦!
Oracle Berkeley DB将于2010年3月底发布最新版本Oracle Berkeley DB 11g release 2,具体版本号为 11.2.5.0.xx (xx代表具体的patch版本号)。
除了对原有Oracle Berkeley DB的功能进行了一定的改进和增强(比如提升了数据压缩功能、性能优化、C/C++中系统资源自动管理功能等等),本次发布的版本中最引人瞩目的变化是我们引入了一个有用的新特性——Oracle Berkeley DB SQL,简称DBSQL (纠正:将原BDBSQL纠正为DBSQL)。这是自Berkeley DB诞生20多年来第一次支持SQL接口。这无论是对开源社区,还是对嵌入式数据库行业来说,都将是一件喜事。在此也感谢整个Oracle Berkeley DB 研发团队的努力工作和大家的不断支持。
新的版本,新增的SQL接口,值得期待。
Oracle Berkeley DB SQL接口简介
从Oracle Berkeley DB (简称BDB)诞生以来,它一直扮演着一个嵌入式、提供API调用的、高性能、非关系型的数据库引擎的角色, 被广泛应用于存储、金融、互联网、电子商务、汽车、消费电子、航空及国防等领域。简言之,它是一个1M大小的C语言类库,提供了基于键/值对(key/value pair)形式的并发和事务操作的API给C/C++/Java/C#/PHP等编程语言调用。由于BDB灵活高效的特点,它特别适合一些大数据量的、或者任务密集型的、或者硬件资源受限而性能要求高的嵌入式、跨平台等等的应用需求。
但我们发现,在很多场合对于关系数据库和SQL的需求是大量存在的。在 “edge”(如消费电子)或者一些大型的企业应用(如ERP)中,一个即时高效、并发的,支持SQL的、本地化嵌入式数据库通常是首选。因此,从 Oracle Berkeley DB 11g release 2开始,我们在保留原有基于key/value操作的API的同时,新增加了对SQL的支持。
DBSQL完全兼容SQLite(著名的嵌入式开源关系数据库)原有的编程接口。以往运行在SQLite上的程序和应用都可以无缝的、方便的迁移到 Oracle Berkeley DB这个更加强大的引擎。并且,Oracle Berkeley DB和SQLite还将进行长期的官方层面的合作,保证了Oracle Berkeley DB的SQL接口和SQLite保持一致,免除了用户的后顾之忧。此外,Berkeley DB SQL完美支持很多第三方的SQLite工具,如JDBC,ODBC,FireFox 3及其SQLite Manager 插件等。
就具体实现来说,在DBSQL中,我们将原SQLite的底层存储引擎替换为Berkeley DB的数据库引擎。如下图所示:
从上面的DBSQL实现图可以看到,Oracle Berkeley DB引入了SQLite的SQL层:包括用户接口(sqlite3(), ODBC, JDBC等)和SQL语言处理层(Tokenizer、Parser及Generator),而底层引擎(虚拟机)则使用了BDB的存储引擎。从而,将原来SQLite基于数据库级别的并发提升一个级别 - 至BDB的基于页(Page)级别的并发,并可以利用BDB的更好的内存管理、数据和事务恢复功能、更多的扩展(如Berkeley DB的db_hotbackup、db_stat、db_archive等一系列命令行工具)。
Oracle Berkeley DB 11g release 2在主流平台经过了严格的、多重的测试和认证(每个平台涵盖以十万计的测试案例),测试平台包括Solaris、*nix、Windows系列(XP, 7, Mobile)、Android 2.0(及以上)、VxWorks等等。此外,我们还提供了大量工具和资料帮助用户熟悉这套最新接口。随版本一起发布的,包括SQLite到Oracle Berkeley DB数据迁移指南、JDBC/ODBC使用指南、全文检索(Full Text Search)向导、空间数据库(R*Tree)向导、Android平台上使用向导、数据库使用手册及调优向导、数据管理员手册、测试集、代码示例等完善的资料,进一步帮助用户放心地来使用我们的产品。了解更多SQLite的语法、API、命令行等帮助,还可以参考SQLite.org上的文档。
总结一下: DBSQL接口是一个1M大小的C语言类库,是一个高效并发的嵌入式数据库。它支持in-memory cache选项,某些场合可作为内存数据库的一个替代方案。它支持C/C++/Java/PHP等语言接口和通过JDBC/ODBC等驱动程序访问。它运行于Unix/POSIX、Windows家族、VxWorks、QNX、Android等平台。和SQLite一样,它支持SQL92标准。
Berkeley DB SQL和SQLite使用上的区别
a) 对于用户和开发人员来说,这两个产品是没有区别的。它们在SQL语法、API、命令行交互、PRAGAMAs 等方面都是一致的。我认为,用户可以体验的显著区别有可能是性能和并发了 - 由于SQLite提供的是数据库级别的锁,而Berkeley DB SQL是页(Page)级别的锁,因此后者在绝大多数测试中都会快很多 (如Insert, Update, Delete, 并发操作等)。但是,由于DBSQL提供的细粒度锁的机制,它又会带来一些额外的开销,一些极端的测试用例下会比SQLite慢上少许(但不明显)。并且对于这些极端测试的案例,我们一直在进行性能优化。
b) 对于已有的SQLite应用程序和工具而言,由于这两者在调用接口都是一致的,因而都可以无缝支持。
c) 对于DBA人员来说,除了可以继续使用SQLite原来的管理工具,您还可以使用BDB提供的db_hotbackup、db_stat、db_archive等一系列命令行工具来备份,监控,升级等。另外,您还可以联系Oracle寻求支持。
总体而言,我们有充分理由相信Oracle Berkeley DB SQL将会比SQLite更快,更稳定。同时,我们也将会提供更好的支持服务。
DBSQL接口和BDB key/value接口的比较
我们举个例子说明这两套API在开发上的区别。
假设有一个employee的BDB数据库(注:一个BDB的数据库,即相当于关系型数据库中的一张二维表),我们定义其主键字段为:key{empId, email},定义其value包含字段:value{empName, sex, age, startDate, status}。相应的,对应于Oracle 关系型数据库的表结构为:
TABLE: employee {
empId PRIMARY KEY,
email PRIMARY KEY,
empName,
sex,
age,
startDate,
status
}
接下来,对于数据库的操作,在BDB的语法大致为:
- 要插入一条记录,employeeDatabase.put(key{1000, john.smith@foo.com}, value{'John Smith', 'male', 30, 2005-01-01, 'OK'});
- 随后,如果要更新上面那条记录:employeeDatabase.put(key{1000, john.smith@foo.com}, value{'John Smith', 'male', 60, 2005-01-01, 'Retired'});
- 如果删除该条记录,则:employeeDatabase.delete(key{1000, john.smith@foo.com}); // 此处只需要提供key即可
- 查询记录:employeeDatabase.get(key{1000, john.smith@foo.com}); // 此处只需要提供key即可
在DBSQL中,上面的增删改操作都可以通过标准的SQL语言来进行。如更新一条记录,可写成:
update employee set age=60, status='Retired' where empId=1000 and email='john.smith@foo.com';
总结
最后,需要强调的是,DBSQL是作为对BDB已有功能的一个补充而不是替代。它只是本次BDB发布产品的一个新特性,并且将会像Hash、Queue、集群等功能一样持续下去。它的出现在一定程度上更丰富了BDB的应用场景。用户可以根据自己的需要,选择适合的BDB接口:
- 当用户需要非常高的性能,管理非关系型数据,或者以Queue、Hash等方式来组织和访问数据的时候,可以继续选择 Oracle Berkeley DB的既有key/value API。如大型企业系统中单点登录、消息队列、工作流等模块,如管理XML、声音、照片、视频等场合,如SOA中的BAM模块、业务规则引擎,如云计算或者云存储节点上,等等。
- 而在用户需要一个本地持久化的支持SQL的嵌入式数据库时,DBSQL将成为优先的选择。比如,手机的通讯录、个人web站点、桌面端 的应用(如股票软件、浏览器客户端的缓存和存储)及开发工具(如IDE)、中小企业的数据库系统、企业实时系统的一些缓存模块、小型的关系型内存数据库等 等。
正式版本的Oracle Berkeley DB 11g release 2将于2010年3月底发布。Oracle Berkeley DB整个产品家族继续以开源形式发布,并对开源社区提供支持。更多关于Oracle Berkeley DB 11g release 2的新功能和特性,请关注我们的官方网站(http://www.oracle.com/database/berkeley-db/index.html)或者本博客的后续文章。
请至官方网站下载最新版本的Oracle Berkeley DB数据库系列产品,包括Oracle Berkeley DB (及SQL),Oracle Berkeley DB Java版和Oracle Berkeley DB XML数据库。
更多需求和反馈,欢迎留言或者给我发邮件:chao.huang[at]oracle.com。

@linchunsun
非常感谢您的回答,我已经用c#API完成了需求,感觉比SQL方式更好
@liao5930
我碰到的问题和你一样,如何才能联系到你?
c# 版 的 DBD
报错:尝试读取或写入受保护的内存。这通常指示其他内存已损坏
具体是什么原因,
而且能不能提供一个多线程访问的实例呀,
谢谢了
有没有python的封装呀?默认python自带的bdb好像版本很老。
@yang
我看到你在2个版面问了关于BDB Python接口的2个问题。我在此一并回答。
BDB的key-value 接口没有专门针对Python的封装。但是Python有一个bsbdb的模块,是用来操作BDB的key-value 接口的。链接为 http://docs.python.org/library/bsddb.html.
针对于BDB的SQL接口,你还可以通过Python的sqlite3接口来使用。你只需要将SQLite的类库替换成DBSQL的库,即可正常使用。当然,如果有历史数据的话,你需要先将数据迁移到DBSQL (导入/导出)。Python的sqlite3接口的链接是 http://docs.python.org/release/3.0.1/library/sqlite3.html.
非常感谢你的解答!
我已经替换python/dlls/sqlite3.dll为libdb_sql51.dll,
并且能成功执行sql操作了。
不过又引发了两个问题,还需要请教:
1. 我测试bdb sql的并发多进程写性能,我发现即使单个进程情况下,用executemany执行也仅能40-50条小数据插入/每秒
2.我用3个进程并发写的时候,测试了2次,其中一次出现了严重错误,说数据库损坏需要修复
我的测试如下:
1. dbsql k
2. 创建表 create table test(name varchar);
3.执行 test.py
test.py如下:
import sqlite3
import time
conn=sqlite3.connect(‘k’)
conn.isolation_level = None #set auto commit
vl=[]
for x in range(100):
vl.append((‘testtesttesttestahahaflsajfdlsajflasjflajflasjfa’,))
for x in xrange(100):
if x % 10 == 0:
print x,”->”,time.ctime()
conn.executemany(”’ insert into test values (?) ”’,vl)
conn.close()
—–end py—-
出错时信息如下:
D:\tmp>python test.py
0 -> Fri Jan 21 23:15:37 2011
10 -> Fri Jan 21 23:16:01 2011
20 -> Fri Jan 21 23:16:26 2011
30 -> Fri Jan 21 23:16:51 2011
40 -> Fri Jan 21 23:17:17 2011
50 -> Fri Jan 21 23:17:42 2011
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: PANIC: fatal region error detected; run recovery
Traceback (most recent call last):
File “test.py”, line 11, in
conn.executemany(‘ insert into test values (?) ‘,vl)
sqlite3.DatabaseError: database disk image is malformed
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: File handles still open at environment close
D:\tmp\k: Open file handle: D:\tmp\k-journal\..\k
D:\tmp\k: Open file handle: D:\tmp\k-journal\log.0000000003
D:\tmp\k: PANIC: fatal region error detected; run recovery
我用的是Berkeley DB 11gR2 5.1.19,测试在windows xp sp3上。
D:\tmp\k: PANIC: fatal region error detected; run recovery
这个问题我现在能稳定重现了,麻烦帮忙看看有什么解决方法,谢谢先。
步骤1:
d:>tmp>dbsql k
create table test(name);
.quit
步骤2:在一个cmd窗口
D:\tmp>python test.py 200 插入2000条记录(程序每次插入10条,插200次)
步骤3:在cmd窗口运行 python test.py 2000000 ,让这个进程一直运行中
同时步骤4:在另一个cmd窗口中:
a) d:\tmp> dbsql k
select * from test;
在打印test的记录过程中Ctrl+C,强制退出dbsql
b)再次运行 d:\tmp> dbsql k
再次运行 select * from test;
于此同时,上面那个窗口运行中的test.py会立刻错误并退出并打印信息:
sqlite3.DatabaseError: database disk image is malformed
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: PANIC: fatal region error detected; run recovery
D:\tmp\k: File handles still open at environment close
D:\tmp\k: Open file handle: D:\tmp\k-journal\..\k
D:\tmp\k: Open file handle: D:\tmp\k-journal\log.0000000003
D:\tmp\k: PANIC: fatal region error detected; run recovery
还有一种情况也会触发:
用下面这个程序:
import sqlite3
import time
import sys
conn=sqlite3.connect(‘k’)
conn.isolation_level = None
vl=[]
n=int(sys.argv[1])
print n
for x in range(100):
vl.append((‘testtesttesttestahahaflsajfdlsajflasjflajflasjfa’,))
def write(task, n):
import sqlite3
import time
conn=sqlite3.connect(‘k’)
conn.isolation_level = None
for x in xrange(n):
print task, ‘:’, x,”->”, time.ctime()
c=conn.cursor()
c.executemany(”’ insert into test values (?) ”’,vl)
”’
dbsql k
create table test(name);
”’
import thread
xx = thread.start_new_thread(write,(1,10000))
yy = thread.start_new_thread(write,(2,10000))
time.sleep(100000)
在两个cmd窗口同时运行:
python test2.py 1000
在其中一个窗口Ctrl+C,中断运行,然后再次运行,这时另一个cmd窗口中的程序就报错了!
@yang
你好,请问你的python具体版本,还有操作系统版本(Win32 / Win 64)? 我会看看问题是否可以重现。
python 2.5 windows xp sp3 32位
应该能重现,我很多客户机器上都出现了这个问题。
谢谢先。
@yang
你好,我已建立好测试环境。
在论坛上贴出的源码程序有全半角/格式的问题,欢迎把三进程并发的程序发到我的邮箱,rucong.zhao@oracle.com. 我会检查这个问题并给你回复。谢谢。
在 BerkeleyDB.DatabaseException.ThrowException(Int32 err)
在 BerkeleyDB.Internal.DB.open(DB_TXN txn, String file, String database, DBTYPE type, UInt32 flags, Int32 mode)
在 BerkeleyDB.BTreeDatabase.Open(String Filename, String DatabaseName, BTreeDatabaseConfig cfg, Transaction txn)
在 BerkeleyDB.BTreeDatabase.Open(String Filename, BTreeDatabaseConfig cfg)
在 IMLib.BerkeleyDB.BerkeleyDBHelper..ctor(String dbName)
@weis
Hi,
我不是很清楚你遇到什么问题。 请将具体的错误描述,使用场景和环境(如OS、JDK、memory等),和系统配置(如cache size等)发到我邮箱。如果有一个程序可以重现你的问题,那更好。chao[dot]huang[at]oracle[dot]com。
英文好的话,鼓励你到BDB官方论坛发问。
您好:
在文中您提到Berkeley DB有in-memory cache功能,可以作为小型的内存数据库使用,我想问下在BDB作为内存数据库使用的时候,其支持的最大容量是多少啊?在存取性能上有测试数据吗?
Ps:
有没有BerkeleDB的QQ群啊?
谢谢
@adamsjtu
上海交大的?如果是交大的高材生,建议直接读BDB英文文档。你的问题都应该可以找到答案的。
具体性能指标可以参考我们的性能白皮书 – 在http://www.oracle.com/technetwork/database/berkeleydb/overview/index-085366.html底部的“Oracle Berkeley DB: Performance and Configuration Options”那一栏。
@chaohuang
您好:
我在运行db-5.2.28源码里提供的例子ex_sql_multi_thread(/db-5.2.28/examples/sql/c/ex_sql_multi_thread.c)时会发现偶尔丢行。
正常运行结果应该如下:
Check existing record number of the table
SQL: SELECT count(*) FROM university;
100025
但是偶尔会丢一到两行:
Check existing record number of the table
SQL: SELECT count(*) FROM university;
100024
发生几率差不多7‰.
并且在运行过程中,有时候会出现这样的log:DB_LOCK->lock_put: Lock is no longer valid
我的运行环境是:
CentOS6
$ uname -a
Linux localhost.localdomain 2.6.32-71.el6.x86_64 #1 SMP Fri May 20 03:51:51 BST 2011 x86_64 x86_64 x86_64 GNU/Linux
Berkeley DB version: db-5.2.28
编译时选项:
../dist/configure –enable-sql_compat –enable-test –with-tcl=/usr/lib64
您有邮箱吗或是QQ吗? 能否详细讨论?
谢谢!
你好,请问程序运行在什么文件系统上?欢迎来信讨论(rucong.zhao@oracle.com), 谢谢
ext4
# file -s /dev/dm-2
/dev/dm-2: Linux rev 1.0 ext4 filesystem data (needs journal recovery) (extents) (large files) (huge files)
@chaohuang
您好,是运行在etc4上的。
在跑程序时仅仅是修改了源代码中ex_sql_multi_thread.c的main()函数:
修改如下:
int
main()
{
db_handle *db;
const char* db_name = “ex_sql_multi_thread.db”;
/* Check if current lib is threadsafe. */
if(!sqlite3_threadsafe()) {
fprintf(stderr,
“ERROR: The libsqlite version is NOT threadsafe!\n”);
exit(EXIT_FAILURE);
}
int try_times = 1000, try_step = 0;
for(try_step = 0; try_step < try_times; try_step ++){
printf("Exl_sql_multithread test: step = %d\n", try_step);
/* Setup environment and preload data. */
db = setup(db_name);
load_table_from_file(db, university_sample_data, 1/* Silent */);
/* Run example. */
ex_sql_multi_thread(db, db_name);
/* End. */
cleanup(db);
}
return 0;
}
后来通过ramdisk,在ramdisk系统上创建了ext3以及ext2文件系统,分别跑上面的程序,也会出现上面所提的丢行问题
不好意思,打错字了,是ext4,不是etc4
我调用了commit语句后,发现数据没有写到硬盘中。不知道是什么原因引起的。我用的BDB 支持SQL的版本,版本号是db-5.1.19.
代码如下:
1
sqlite3 * m_pDB;
int nRet = sqlite3_open_v2(strDBName.c_str(), & m_pDB,SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,NULL);
2
string strSQL=”CREATE TABLE [TBLClientAccount] ( [ClientId] CHAR (36), [AccountId] CHAR (36) );”;
char * errors;
nRet = sqlite3_exec(m_pDB, strSQL.c_str(), NULL, NULL, &errors);
3
nRet = sqlite3_exec(m_pDB, “begin;”, NULL, NULL, &errors);
4
nRet = sqlite3_exec(m_pDB, “INSERT INTO TBLClientAccount (ClientId,AccountId) VALUES(‘dd’,'ddd’); “, NULL, NULL, &errors);
5
nRet = sqlite3_exec(m_pDB, “commit;”, NULL, NULL, &errors);
6 拷贝数据库文件到d盘,然后用bdb自带的dbsql这个工具去打开数据。
我用select 语句,发现insert 的数据并没有写到表中。难道调用commit语句后,数据不会立刻写到硬盘中吗?
@leon
事物提交后的数据是否立即写到磁盘上,这取决于你的事务持久性(Durability)设置。具体可以参考 http://www.bdbchina.com/2010/12/bdb-je%E4%BA%8B%E5%8A%A1%E7%9A%84%E6%8F%90%E4%BA%A4%E6%96%B9%E5%BC%8F%E6%A6%82%E8%BF%B0/
虽然文章是针对BDB-JE,但是原理是相通的。为了让你的实验可以顺利进行,请设置事务持久性到Sync,然后再试。当然这样会降低性能。
请教个基本的问题, 使用DB 句柄或者游标句柄写数据的时候,默认的情况下,是不是对cache的回写机制?如果保证同步写入呢?谢谢。
jdbc操作的数据库没问题,在bin目录下的dbsql.exe 读取 jdbc操作的数据后就会造成 jdbc无法读取的情况
C:\Program Files\Oracle\Berkeley DB 11gR2 5.2.36\bin>dbsql d:\db2
Berkeley DB 11g Release 2, library version 11.2.5.2.36: (September 14, 2011)
Enter “.help” for instructions
Enter SQL statements terminated with a “;”
dbsql> select * from test;
Error: file is encrypted or is not a database
dbsql> .exit
你好,
我在使用Oracle Berkeley DB 11g release 2中遇到问题,找不到答案。具体问题如下:
使用JDBC操作bdb 遇到高并发压力瓶颈,硬盘读写频繁,oracl 的3000并发写入查询没有压力,dbd就严重超时。环境Berkeley DB 11gR2 5.2.36,WIN7 32位系统。
现在解决不了这个问题后,就打算换成KEY,VALUE的操作方式去做,但是又出现另外问题,key,value操作生成的数据库,如何用dbsql.exe读出?jdbc能否读取出?
因为业务有需求可能这些接口都需要用到.请帮忙.
您好
版本 Berkeley DB 11gR2 5.2.36
发现了些问题,当并发2000时候单表一个字段,插入数据可以,硬盘灯常亮。建立sequence为主键,用select
nextval(“seq_vip_interface_log”); 与插入同时操作50后就会出现
c:\bdb\bdbtest.db:BDB0113 Thread/process 3724/3868 failed: BDB1507
Thread died i
n Berkeley DB library
后来用 primary key autoincrement 建表后就可以过,不过出现 java.sql.SQLException:
SQLite.Exception: database table is locked
@santafeng
你好,感谢你的回馈。如果是技术问题,我建议你发布到官网论坛;或者也可以发邮件给我。邮件地址见上面评论。
cheng大师:你好,我初次接触BDB,由于工作需要使用BDB JE HA,我之前又从来没有接触过关于集群方面的东西,我照着BDB JE 中关于 HA 的示例程序做了一个测试,只能在localhost运行,如果我使用两台机器去做,在使用JVM运行的时候就一直不动了,非常希望cheng大师能帮帮我,谢谢~~~
之后还想使用多线程运行HA的东西,希望大师指导,哎~~~
@chaohuang
chao大师:你好,我初次接触BDB,由于工作需要使用BDB JE HA,我之前又从来没有接触过关于集群方面的东西,我照着BDB JE 中关于 HA 的示例程序做了一个测试,只能在localhost运行,如果我使用两台机器去做,在使用JVM运行的时候就一直不动了,非常希望cheng大师能帮帮我,谢谢~~~之后还想使用多线程运行HA的东西,希望大师指导,哎~~~
@tiend
这个你的去读文档,按照文档的说明一步一步进行。我相信你只要花到时间了,就一定可以的。如果你有具体的问题,咱们可以邮件讨论。
@chaohuang
谢谢,之前的问题弄好了,我只要把之前生成的数据库文件删除,就可以了(我不知道是不是由于数据库环境锁?【是这个名词吗?】的原因),用示例程序做了集群的性能测试,和不使用集群性能差别很大,不知道这个是什么原因,是我什么地方没有弄对吗?我是这样做的,一台单独的机器运行HARouter,另外一台机器运行三个数据库节点,插入10万条数据:
机器环境(CentOS Linux release 6.0 (Final))
Memory:4G
Intel(R) Core(TM) i3-2100 CPU @ 3.10GHz
使用HARouter进行负载均衡,一共花了22秒;如果不用集群的话平均7秒的样子
我看资料说集群不能使用多线程,是这样的吗?还有如果运行了事务也不能;官方的文档中关于锁的我看了,可能是我英文水平有限,好像没什么帮助
@chaohuang
大师,我还不知道你的邮箱诶,可以告诉我么?