`
dylan.wu
  • 浏览: 135765 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Berkeley DB初探

阅读更多

前言

最近一个一个相似文章搜索功能时,要保存文章库的向量矩阵,由于矩阵太大无法一次加载到内存中,加上项目属于轻量级。总结了一下需求其实很简单,就是从一个非常大的矩阵中(无法一次性加载到内存),每次会随机通过文章编号得到其tfidf向量(矩阵的一行数据)。发现嵌入式数据库Berkeley DB可以很好的满足我的需求。只要把文章编号看成key,tfidf向量看成data,就可以利用Berkeley DB实现我的需求。

UNIX/LINUX平台下的数据库种类非常多,参考资料1中列举了其中的大部分。通常,我们在设计UNIX/LINUX平台下的应用软件时,如果数据种类繁多,数据与数据之间关系比较复杂,就会选用一些大型的企业级数据库系统,如DB2,ORACLE、SYBASE等,如果软件规模不大,就倾向选用如MYSQL、POSTGRESQL等中小型数据库。例如使用PHP/PERL + MYSQL/POSTGRESQL设计网站基本上是一个很常规的做法。但是,当应用软件管理的数据类型较少(特别注意:这并不是说需要管理的数据量小),数据管理本身不复杂,且对数据操作要求高效率,则由大名鼎鼎的Berkeley(美国加州大学伯克利分校)开发的 Berkeley DB可能是一个很明智的选择。

DB综述

DB最初开发的目的是以新的HASH访问算法来代替旧的hsearch函数和大量的dbm实现(如AT&T的dbm,Berkeley的ndbm,GNU项目的gdbm),DB的第一个发行版在1991年出现,当时还包含了B+树数据访问算法。在1992年,BSD UNIX第4.4发行版中包含了DB1.85版。基本上认为这是DB的第一个正式版。在1996年中期,Sleepycat软件公司成立,提供对DB的商业支持。在这以后,DB得到了广泛的应用,当前最新版本是4.3.27。

DB支持几乎所有的现代操作系统,如LINUX、UNIX、WINDOWS等,也提供了丰富的应用程序接口,支持C、C++、JAVA、PERL、TCL、PYTHON、PHP等。DB的应用十分广泛,在很多知名的软件中都能看到其身影。例如参考资料2中作者谈到利用DB在LINUX下实现内核级文件系统;参考资料3中通过实际测试数据说明DB提高了OPENLDAP的效率。LINUX下的软件包管理器RPM也使用DB管理软件包相关数据,可以使用命令file查看RPM数据目录/var/lib/rpm下的文件,则有形式如下的输出:

Dirnames: Berkeley DB (Btree, version 9, native byte-order) 
Filemd5s: Berkeley DB (Hash, version 8, native byte-order)

值得注意的是DB是嵌入式数据库系统,而不是常见的关系/对象型数据库,对SQL语言不支持,也不提供数据库常见的高级功能,如存储过程,触发器等。

DB的设计思想

DB的设计思想是简单、小巧、可靠、高性能。如果说一些主流数据库系统是大而全的话,那么DB就可称为小而精。DB提供了一系列应用程序接口(API),调用本身很简单,应用程序和DB所提供的库在一起编译成为可执行程序。这种方式从两方面极大提高了DB的效率。第一:DB库和应用程序运行在同一个地址空间,没有客户端程序和数据库服务器之间昂贵的网络通讯开销,也没有本地主机进程之间的通讯;第二:不需要对SQL代码解码,对数据的访问直截了当。

DB对需要管理的数据看法很简单,DB数据库包含若干条记录,每一个记录由关键字和数据(KEY/VALUE)构成。数据可以是简单的数据类型,也可以是复杂的数据类型,例如C语言中结构。DB对数据类型不做任何解释, 完全由程序员自行处理,典型的C语言指针的"自由"风格。如果把记录看成一个有n个字段的表,那么第1个字段为表的主键,第2--n个字段对应了其它数据。DB应用程序通常使用多个DB数据库,从某种意义上看,也就是关系数据库中的多个表。DB库非常紧凑,不超过500K,但可以管理大至256T的数据量。

DB的设计充分体现了UNIX的基于工具的哲学,即若干简单工具的组合可以实现强大的功能。DB的每一个基础功能模块都被设计为独立的,也即意味着其使用领域并不局限于DB本身。例如加锁子系统可以用于非DB应用程序的通用操作,内存共享缓冲池子系统可以用于在内存中基于页面的文件缓冲。

DB核心数据结构

数据库句柄结构DB:包含了若干描述数据库属性的参数,如数据库访问方法类型、逻辑页面大小、数据库名称等;同时,DB结构中包含了大量的数据库处理函数指针,大多数形式为 (*dosomething)(DB *, arg1, arg2, …)。其中最重要的有open,close,put,get等函数。

数据库记录结构DBT:DB中的记录由关键字和数据构成,关键字和数据都用结构DBT表示。实际上完全可以把关键字看成特殊的数据。结构中最重要的两个字段是 void * data和u_int32_t size,分别对应数据本身和数据的长度。

数据库游标结构DBC:游标(cursor)是数据库应用中常见概念,其本质上就是一个关于特定记录的遍历器。注意到DB支持多重记录(duplicate records),即多条记录有相同关键字,在对多重记录的处理中,使用游标是最容易的方式。

数据库环境句柄结构DB_ENV:环境在DB中属于高级特性,本质上看,环境是多个数据库的包装器。当一个或多个数据库在环境中打开后,环境可以为这些数据库提供多种子系统服务,例如多线/进程处理支持、事务处理支持、高性能支持、日志恢复支持等。

DB中核心数据结构在使用前都要初始化,随后可以调用结构中的函数(指针)完成各种操作,最后必须关闭数据结构。从设计思想的层面上看,这种设计方法是利用面向过程语言实现面对对象编程的一个典范。

DB数据访问算法

在数据库领域中,数据访问算法对应了数据在硬盘上的存储格式和操作方法。在编写应用程序时,选择合适的算法可能会在运算速度上提高1个甚至多个数量级。大多数数据库都选用B+树算法,DB也不例外,同时还支持HASH算法、Recno算法和Queue算法。接下来,我们将讨论这些算法的特点以及如何根据需要存储数据的特点进行选择。

B+树算法:B+树是一个平衡树,关键字有序存储,并且其结构能随数据的插入和删除进行动态调整。为了代码的简单,DB没有实现对关键字的前缀码压缩。B+树支持对数据查询、插入、删除的常数级速度。关键字可以为任意的数据结构。

HASH算法:DB中实际使用的是扩展线性HASH算法(extended linear hashing),可以根据HASH表的增长进行适当的调整。关键字可以为任意的数据结构。

Recno算法: 要求每一个记录都有一个逻辑纪录号,逻辑纪录号由算法本身生成。实际上,这和关系型数据库中逻辑主键通常定义为int AUTO型是同一个概念。Recho建立在B+树算法之上,提供了一个存储有序数据的接口。记录的长度可以为定长或不定长。

Queue算法:和Recno方式接近, 只不过记录的长度为定长。数据以定长记录方式存储在队列中,插入操作把记录插入到队列的尾部,相比之下插入速度是最快的。

对算法的选择首先要看关键字的类型,如果为复杂类型,则只能选择B+树或HASH算法,如果关键字为逻辑记录号,则应该选择Recno或Queue算法。当工作集关键字有序时,B+树算法比较合适;如果工作集比较大且基本上关键字为随机分布时,选择HASH算法。Queue算法只能存储定长的记录,在高的并发处理情况下,Queue算法效率较高;如果是其它情况,则选择Recno算法,Recno算法把数据存储为平面文件格式。

DB常用函数使用范例

 

 

#include <db.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

void print_error(int ret) {
	if (ret != 0) {
		printf("Error: %s\n", db_strerror(ret));
	}
}

void init_DBT(DBT* key, DBT* data) {
	memset(key, 0, sizeof(DBT));
	memset(data, 0, sizeof(DBT));
}

int main() {
	DB* dbp;
	DBT key, data;
	u_int32_t flags;
	int ret;
	char* fruit = "apple";
	int number = 15;
	typedef struct customer {
		int c_id;
		char name[10];
		char address[20];
		int age;
	} Customer;
	Customer cust;
	int key_cust_c_id = 1;
	cust.c_id = 1;
	strncpy(cust.name, "javer", 9);
	strncpy(cust.address, "chengdu", 19);
	cust.age = 32;
	// create db hander
	ret = db_create(&dbp, NULL, 0);
	print_error(ret);

	// create db flags
	flags = DB_CREATE;
	// create a db named single.db with B+ tree.
	ret = dbp->open(dbp, NULL, "single.db", NULL, DB_BTREE, flags, 0);
	print_error(ret);
	init_DBT(&key, &data);
	
	key.data = fruit;
	key.size = strlen(fruit) + 1;
	data.data = &number;
	data.size = sizeof(int);
	
	ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE);
	print_error(ret);
	
	//dbp->sync(dbp);
	
	init_DBT(&key, &data);
	key.data = fruit;
	key.size = strlen(fruit) + 1;

	ret = dbp->get(dbp, NULL, &key, &data, 0);
	print_error(ret);
	// the name type of DBT's data is void*.
	printf("The number = %d\n", *(int*)(data.data));
	
	if (dbp != NULL) {
		dbp->close(dbp, 0);
	}

	ret = db_create(&dbp, NULL, 0);
	print_error(ret);
	flags = DB_CREATE;
	// create a db names "complex.db" with hash.
	ret = dbp->open(dbp, NULL, "complex.db", NULL, DB_HASH, flags, 0);
	print_error(ret);
	init_DBT(&key, &data);
	key.size = sizeof(int);
	key.data = &(cust.c_id);
	data.size = sizeof(Customer);
	data.data = &cust;
	ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE);
	print_error(ret);

	memset(&cust, 0, sizeof(Customer));
	
	key.size = sizeof(int);
	key.data = &key_cust_c_id;
	data.data = &cust;
	data.ulen = sizeof(Customer);
	data.flags = DB_DBT_USERMEM;
	dbp->get(dbp, NULL, &key, &data, 0);
	print_error(ret);

	printf("c_id = %d name = %s address = %s age = %d\n",
		cust.c_id, cust.name, cust.address, cust.age);
	if (dbp != NULL) {
		dbp->close(dbp, 0);
	}

	typedef struct Pair {
		long key;
		double value;
	} Pair;
	Pair pairs[3] = {{1, 0.1}, {2, 0.2}, {3, 0.3}};
	ret = db_create(&dbp, NULL, 0);
	print_error(ret);
	flags = DB_CREATE;
	// create a db names "complex2.db" with hash.
	ret = dbp->open(dbp, NULL, "/tmp/complex2.db", NULL, DB_HASH, flags, 0);
	print_error(ret);
	init_DBT(&key, &data);
	key.size = sizeof(int);
	key.data = &(key_cust_c_id);
	data.size = sizeof(Pair) * 3;
	data.data = pairs;
	ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE);
	print_error(ret);

	memset(&cust, 0, sizeof(Customer));
	
	key.size = sizeof(int);
	key.data = &key_cust_c_id;
	dbp->get(dbp, NULL, &key, &data, 0);
	print_error(ret);

	int size = data.size / sizeof(Pair);
	Pair* pp = (Pair*)data.data;
	for (int i = 0; i < size; ++i) {
		printf("key = %ld, value = %f\n", pp[i].key, pp[i].value);
	}
	if (dbp != NULL) {
		dbp->close(dbp, 0);
	}
	return 0;
}
       

 DB游标使用范例

游标是依赖于数据库句柄的,应用程序代码框架如下:

/* 定义一个游标变量 */
DBC * cur;
/* 首先打开数据库,再打开游标 */
dbp->open(dbp, ……);
dbp->cursor(dbp, NULL, &cur, 0);
	
/* do something with cursor */
/* 首先关闭,在关闭数据库 */
cur->c_close(cur);
dbp->close(dbp, 0);

 在游标打开后,可以以多种方式遍历特定记录。

Memset(&key, 0, sizeof(DBT));
Memset(&data, 0, sizeof(DBT));
/* 因为KEY和DATA为空,则游标遍历整个数据库记录 */
While((ret = cur->c_get(cur, &key, &data, DB_NEXT)) == 0)
{
	/* do something with key and data */
}

 当想查询特定关键字对应的记录,则应对关键字赋值,并把cur->c_get()函数中标志位设置为DB_SET。例如:

key.data = "xxxxx";
key.size =  XXX;
While((ret = cur->c_get(cur, &key, &data, DB_SET)) == 0)
{
	/* do something with key and data */
}

 游标的作用还有很多,如查询多重记录,插入/修改/删除记录等。

DB环境使用范例

本文前面已说明环境是DB数据库的包装器,提供多种高级功能。应用程序代码框架如下:

/* 定义一个环境变量,并创建 */
DB_ENV *dbenv;
db_env_create(&dbenv, 0);
  
/* 在环境打开之前,可调用形式为dbenv->set_XXX()的若干函数设置环境 */
/* 通知DB使用Rijndael加密算法(参考资料>)对数据进行处理 */
dbenv->set_encrypt(dbenv, "encrypt_string", DB_ENCRYPT_AES);
/* 设置DB的缓存为5M */
dbenv->set_cachesize(dbenv, 0, 5 * 1024 * 1024, 0);
/* 设置DB查找数据库文件的目录 */
dbenv->set_data_dir(dbenv, "/usr/javer/work_db");
/* 打开数据库环境,注意后四个标志分别指示DB启动日志、加锁、缓存、事务处理子系统 */
dbenv->open(dbenv,home,DB_CREATE|DB_INIT_LOG|DB_INIT_LOCK| DB_INIT_MPOOL|DB_INIT_TXN, 0);
  
/* 在环境打开后,则可以打开若干个数据库,所有数据库的处理都在环境的控制和保护中。
注意db_create函数的第二个参数是环境变量 */
db_create(&dbp1, dbenv, 0);
dbp1->open(dbp1, ……);
db_create(&dbp2, dbenv, 0);
dbp1->open(dbp2, ……);
/* do something with the database */
/* 最后首先关闭打开的数据库,再关闭环境 */
dbp2->close(dbp2, 0);
dbp1->close(dbp1, 0);
dbenv->close(dbenv, 0);

 DB软件的安装和编译

CentOS下运行

yum install db*

 参考资料

http://www.ibm.com/developerworks/cn/linux/l-embdb/index.html

 

分享到:
评论

相关推荐

    Berkeley DB4.8以上各版本

    Berkeley DB是一款由Oracle公司开发的嵌入式数据库系统,被广泛应用于许多软件项目中,尤其是在需要快速、轻量级数据存储解决方案的场景下。它提供了键值对存储模式,适用于构建高性能的数据缓存和数据库应用程序。...

    Berkeley DB数据库最新版

    **Berkeley DB数据库详解** Berkeley DB(简称BDB)是一种高性能、轻量级的嵌入式数据库系统,由Oracle公司开发并维护。它最初在伯克利大学诞生,因此得名“Berkeley DB”。这款数据库系统广泛应用于需要快速、可靠...

    Berkeley DB数据库 6.2.32 64位

    Berkeley DB 6.2.32_64.msi Windows 64-bit binary installer Berkeley DB是一个嵌入式数据库,为应用程序提供可伸缩的、高性能的、有事务保护功能的数据管理服务。 主要特点: 嵌入式:直接链接到应用程序中,与...

    berkeley db db-6.1.26.tar.gz

    db-6.1.26.tar.gz berkeley db

    Berkeley DB 5.3.21.tar

    Berkeley DB 5.3.21.tar,你也可以去http://www.oracle.com/technetwork/products/berkeleydb/downloads/index.html下载最新版

    BerkeleyDB测试程序

    **BerkeleyDB测试程序** BerkeleyDB是一款轻量级、高性能、嵌入式的数据库系统,由Oracle公司开发。它提供了一种键值对存储模型,适用于需要快速存取大量数据的应用场景,尤其在分布式系统、嵌入式系统以及对性能有...

    Berkeley DB C++编程入门教

    在“BerkeleyDB概念”部分,文档会介绍Berkeley DB的基本概念,如BTree和Hash数据库的访问方式选择,以及Queue和Recno之间的选择。 接下来,教程会讨论数据库的限制与可移植性、环境设置、异常处理和错误返回。然后...

    Berkeley DB参考资料

    BerkeleyDB 多库联合操作 (Secondary Databases) - **3.1 二级数据库介绍** - **概念解释**:二级数据库是对主数据库的一个索引,用于提高查询效率。 - **应用场景**:快速查找、数据统计等。 - **3.2 创建二级...

    Berkeley DB参考手册PDF版本

    #### 1.1 Introduction to BerkeleyDB Cursor - **定义与作用**:游标是Berkeley DB提供的一种高效访问数据库记录的方式,通过游标可以实现对数据库中记录的查找、修改和删除等操作。 - **应用场景**:适用于需要...

    BerkeleyDB的参考书集

    《BerkeleyDB的参考书集》是一份包含全面的BerkeleyDB相关书籍和文档的资源集合,涵盖了从基础到高级的各个层次,旨在为开发者提供深入理解和应用BerkeleyDB的全面指南。BerkeleyDB,简称BDB,是一个开源的、高性能...

    BerkeleyDB Manual C/C++

    《BerkeleyDB Manual C/C++》是一份详尽的官方文档,主要针对使用C和C++语言进行数据库操作的开发者。BerkeleyDB是一款轻量级、高性能的关系型数据库管理系统,常用于嵌入式系统和分布式应用程序。这篇手册将深入...

    sqlite PK Berkeley DB

    ### sqlite与Berkeley DB的深度比较 在信息技术领域,数据库技术是支撑现代软件应用的关键基石之一,其中,sqlite和Berkeley DB作为两款优秀的开源嵌入式数据库管理系统,因其轻量级、高性能及易于集成的特性,在...

    Berkeley DB 读取样例

    Berkeley DB 是一款高效、轻量级的嵌入式数据库系统,特别适合于需要本地存储且对性能有高要求的应用程序。它支持多种编程语言,包括Java,这使得开发人员能够在Java应用程序中直接使用Berkeley DB进行数据管理。在...

    Berkeley DB 4.8.30

    3. **编译**:进入解压后的目录,执行`./configure --prefix=/usr/local/BerkeleyDB.4.8`进行配置,指定安装路径,然后使用`make`进行编译,最后用`sudo make install`安装。 4. **配置Open LDAP**:在Open LDAP的...

    SQL 开发人员 Oracle Berkeley DB 指南

    《SQL开发人员Oracle Berkeley DB指南》 Oracle Berkeley DB是一个开源的嵌入式数据库引擎,它提供了高效、可靠的本地持久性存储,无需独立的数据库管理系统。这个数据库引擎特别适合那些需要固定查询模式并且对...

    Berkeley DB Java 版 4.0.92

    Oracle Berkeley DB Java 版是一个开源的、可嵌入的事务存储引擎,是完全用 Java 编写的。与 Oracle Berkeley DB 类似,Oracle Berkeley DB Java 版在应用程序的地址空间中执行,没有客户端/服务器通信的开销,从而...

    BerkeleyDB-0.26

    **BerkeleyDB** 是一款由 Oracle 公司开发的开源、高性能、无模式的键值对存储数据库系统。它在嵌入式环境和轻量级应用程序中被广泛使用,尤其适用于那些需要快速数据访问和简单数据管理的应用。BerkeleyDB 的设计...

    BerkeleyDB_java_jar包

    BerkeleyDB是一个开源的、基于键值对的嵌入式数据库系统,由Oracle公司提供。它为Java开发者提供了丰富的API,使得在Java应用程序中轻松集成数据存储成为可能。标题中的"BerkeleyDB_java_jar包"指的是适用于Java开发...

    Berkeley DB

    **Berkeley DB** 是一个强大的、轻量级的嵌入式数据库系统,由Oracle公司开发。这个数据库系统设计用于在本地应用程序中存储和检索大量数据,尤其适合那些对性能、可扩展性和可靠性有高要求的应用。它不依赖于外部...

Global site tag (gtag.js) - Google Analytics