Python中的Berkeley DB(2):数据结构

原创 2016年05月30日 09:56:14

Berkeley DB的数据存储结构

BDB支持四种数据存储结构及相应算法,官方称为访问方法(Access Method),分别是哈希表(Hash Table)、B树(BTree)、队列(Queue)、记录号(Recno)。在创建数据库的时候,必须通过dbtype参数将存储结构指定为上述结构中的一种,一旦数据库文件已创建则不能再更改其结构。

结构 描述
BTree 数据存储在一个有序的,平衡的树型结构中。在B树结构中,Key和Value都可以复杂的数据,这意味着它们可以是整数、字符串或复杂的数据结构。同时,这种结构允许重复的Key值,即两个记录拥有同样的Key(需要在创建数据库时打开XXX开关)。
哈希 数据存储在一个扩展的线性哈希表。同B树类似,Key和Value可以是复杂的数据,它也支持相同Key的记录(需要打开XXX)
队列 数据存储在一个固定记录长度的队列中。每个记录使用一个逻辑记录号作为它的Key。这种结构有利于快速在尾部插入,而且针对这种结构有一个专用的操作可以让你从队列头部删除并返回数据。这种结构的特点在于它提供记录级的锁,这非常有利于在并发访问队列时提供更高的性能。
记录号 基本同队列类似,它也使用一个逻辑记录号作为Key,但这里的记录可以是定长的,也可以是不定长的

B树(BTree)

通过指定dbtype=db.DB_BTREE用哈希表作为存储结构。B树中的B是Balanced的缩写,这意味着B树同其它树型结构的区别在于它的叶子节点是平均分布的,即不会出现某个分支很短,另外的分支很长的情况,这种结构非常有利于数据的快速定位。
![一个典型的BTree结构][1]
BDB中实现了B树的数据存储结构和相应算法,从下面的语句中可以看出,实际使用过程中,B树同哈希表基本一样。

>>> from bsddb import db  
>>> mydb = db.DB()  
>>> mydb.open('btree.db',dbtype = db.DB_BTREE, flags = db.DB_CREATE)
>>> mydb.put("number1","1")
>>> mydb.put("number2","2")
>>> print mydb.items()
[('number1', '1'),('number2', '2')]
>>> mydb.put("number1","123")       #注:可以直接用put方法修改数据
>>> print mydb.items()
[('number1', '123'),('number2', '2')]
>>> mydb.delete('number1')
>>> print mydb.items()
[('number2', '2')]
>>> print mydb.get('number2')
2

哈希表(Hash)

通过指定dbtype=db.DB_HASH使用哈希表作为存储结构。在上一节中,我们已经接触到这种数据结构。哈希表是一种能够过把键值(Key)映射到表中一个地址来访问记录,即给定一个Key,它通过一个f(Key)函数得到Value的存储地址,它几乎没有遍历或索引的操作,因此能够极快地定位到Key所对应的Value值。下面用一些简单的例子介绍哈希表数据结构的用法。
接着在上一节的Python环境中运行下面的命令:

>>> from bsddb import db  
>>> mydb = db.DB()  
>>> mydb.open('my.db')
>>> print mydb.items()          #打印全部记录
[('title', 'Berkeley DB in Python'), ('author', 'evancss')]
>>> print mydb.get('author')    #获取键名为'author'的值
evancss
>>> mydb.delete('author')       #删除键名为'author'的记录
>>> print mydb.items()
[('title', 'Berkeley DB in Python')]
>>> mydb.close()

队列(Queue)

通过指定dbtype=db.DB_QUEUE使用队列作为存储结构。初次使用这种结构你能感觉到它与B树和哈希有较大的差异。

>>> from bsddb import db
>>> quedb = db.DB()
>>> quedb.open('quedb.db',dbtype=db.DB_QUEUE,flags=db.DB_CREATE)
>>> quedb.put("number1","1")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: String keys not allowed for Recno and Queue DB's
>>>

上面的代码我们新建了一个名字为quedb的队列数据库,在使用我们熟悉的put方法时出错,原因是队列类型是不接受字符串类型的Key名称,Key只能是数字。

>>> quedb.put(1,"first item")
>>> print quedb.items()
[(1, 'first item                              ')]

实际应用中,经常Key对我们来说并不重要,我们可以使用一个简化的append方法向队列添加元素,这个方法会将添加元素的Key(记录号)作为返回值:

>>> quedb.append("second item")
2
>>> print quedb.items()
[(1, 'first item                              '), 
 (2, 'second item                             ')]

在队列中仍可以使用get方法获取值、使用put方法更改值,以及使用delete删除值:

>>> print quedb.get(1)
first item
>>> quedb.put(1,"1st item")
>>> print quedb.items()
[(1, '1st item                                '),
 (2, 'second item                             ')]
>>> quedb.delete(1)
>>> print quedb.items()
[(2, 'second item                             ')]

你可能想让这种数据结构操作起来也更像一个队列。可以使用另一个简化的功能consume,这样我们使用append在队列尾部加入数据,使用consume取出队列首部的数据,很方便地实现了FIFO的操作:

>>> quedb.append("third item")
3
>>> quedb.consume()
('\x02\x00\x00\x00', 'second item                             ')
>>> quedb.consume()
('\x03\x00\x00\x00', 'third item                              ')
>>> quedb.consume()
>>>

记录号

记录号数据结构有些特性和队列很类似,它支持put,get,append,delete等方法,同样,它的Key也只能是数字类型。需要注意的是,在创建数据库之前不需要指定记录长度,它也不能象队列类型那样使用consume方法。

>>> recdb=db.DB()
>>> recdb.open('recdb.db',dbtype=db.DB_RECNO,flags=db.DB_CREATE)
>>> recdb.put(1,"item 1")
>>> recdb.append("item 2")
2
>>> recdb.items()
[(1, 'item 1'), (2, 'item 2')]
>>> recdb.put(2,"item 2nd")
>>> recdb.items()
[(1, 'item 1'), (2, 'item 2nd')]
>>> recdb.delete(2)
>>> recdb.items()
[(1, 'item 1')]
>>>

选择正确的数据结构

首先你要知道准备使用BDB解决什么样的问题,如果你需要存储复杂的数据(包括字符串),那么你应当使用B树或者哈希。如果你想使用逻辑编号,那么应当使用队列或记录号。
那么问题来了,在B树、哈希,队列、记录号之间应当如何做选择呢?

选择B树还是哈希

当记录号不是用于数据存取的主键时,应该使用 Hash和Btree算法。 (如果记录号是用于数据存取的一个二级关键字,那么还是可以选择Btree算法,因为它支持一个主键和一个记录号同时存取。)

Btree中的主键是有序存储,记录间的关联是依靠次序。并且其结构能随数据的插入和删除进行动态调整。为了代码的简单,DB没有实现对关键字的前缀码压缩。Btree支持对数据查询、插入、删除的常数级速度。关键字可以为任意的数据结构。 因此,当在主键有序时,Btree算法应该被使用。例如,如果主键是时间戳, 那么8点时间戳后面跟随的就是9点时间戳, 这种情况下,Btree算法一般是正确的选择。再来个例子:如果主键是名字,应用需要取出所有同姓的记录,那么Btree 存取方法同样是个好选择。

Hash 和 Btree 两种方式在小的数据集合上几乎没有性能的差别。不过,由于Hash使用的是扩展线性HASH算法(extended linear hashing),可以根据HASH表的增长进行适当的调整。所以当一个数据集合足够大且关键字为随机分布时,采用Hash算法比较好。

选择队列还是记录号

当用记录号作为数据存取的主键时,应该使用 Queue和Recno存取方法。记录号由算法本身生成。实际上,这和关系型数据库中逻辑主键通常定义为int AUTO型是同一个概念。两者基本上都是建立在Btree算法之上,提供存储有序数据的接口。Queue的优势在于:由于其记录为定长,在插入操作时把记录插入到队列的尾部,所以速度最快,而且它执行上锁和并发处理的水平也相当高。 Recno 的长处在于它支持一些Queue不能实现的特征,比如可变长记录和支持flat-text文件。

记录号可以是可变的或者不变的: 可变指的是当记录被删除或者插入记录号发生变化;不变指的是记录号无论数据库如何操作,记录号都不会发生改变。 基于记录号存取在Btree方式下也是可行的。但是,记录号是可变,当记录删除或插入时,数据库内的其他记录的记录号都将发生改变。 Queue存取方法总是用固定的方式运行,不管数据库如何操作,记录号始终改变。 Recno 可以被设置为不变和可变两种形式。

另外,Recno为数据库提供支持flat-text文件的永久存储和数据在读或修改时提供一个快速的临时存储空间。

高级特性与线程安全

介绍cursor等
介绍多线程程序中使用的env

Case1:使用Berkeley DB进行URL去重

Case2:使用Berkeley DB作为缓冲队列

PS:实在抱歉,由于最近工作较忙,此系列暂停更新,有兴趣的朋友可以发邮件或留言沟通。

版权声明:本文为博主原创文章,未经博主允许不得转载。

在Python上使用Berkeley DB ——bsddb

前段时间要用最大熵进行自动分词和新词抽取,在处理小文本的时候没什么问题,直接将候选词及其频率、邻接词等信息存入词典放入内存即可。但后来要处理大文本,候选词太多直接导致MemoryError了,就想着先...

Python中的Berkeley DB(1):Hello Berkeley DB

Python中的Berkeley DB – 第一篇:Hello Berkeley DB什么是Berkeley DB1Berkeley DB(后文简称BDB)是一个高性能的嵌入式数据库编程库(引擎),它...
  • langkew
  • langkew
  • 2015年09月16日 00:16
  • 1146

python_使用Berkeley DB数据库

代码: try:     from bsddb import db except ImportError:     from bsddb3 import db print db.DB_VERSION...

berkeley DB +linux +python+bsddb3安装

1,berkeley DB安装 http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloa...

Berkeley DB并发数据存储编程

在完全没有必要用上恢复机制和事件的相关语义时,通常我们会用上可并发存储的数据库.对于这类的程序,BDB提供了释放死锁(deadlock- free),数读/单写(multiple-reader/sin...

Berkeley DB 源代码分析 (3) --- Btree的实现 (2)

__bam_ditem In btree we store on-page duplicate key/data pairs this way: 1. we only put the key...

Berkeley DB 源代码分析 (7) --- 事务和日志 (2)

这篇和上篇一样,也是含有一些wiki格式控制字符,看的时候直接忽略这些格式字符。 = Logging subsystem = == Architecture == Log sub...

基于hadoop MR+berkeley DB实现的十亿级数据的秒级部署和实时查询的解决方案

要解决的问题 1、有10亿级别的某视频网的注册用户和设备用户,需要T+1天的延时后,供前端实时查询任意uid或是设备id对应的用户画像数据。 2、分为计算周期+布署服务化+查询三部分,计算用时优化余地...

python中使用berkeley db的经验总结

http://blog.chinaunix.net/uid-23145525-id-3499930.html 1.选bdb的理由 业务场景是:1个writer进程,多个reader进...
  • s_jobs
  • s_jobs
  • 2013年08月25日 17:56
  • 1592

Berkeley DB 源代码分析 (2) --- Btree的实现 (1)

II. Type Dictionary 1. BTREE The DB handle's DB->bt_internal structure, stores per-process and p...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Python中的Berkeley DB(2):数据结构
举报原因:
原因补充:

(最多只允许输入30个字)