Chinaunix首页 | 论坛 | 博客
  • 博客访问: 301824
  • 博文数量: 47
  • 博客积分: 2455
  • 博客等级: 大尉
  • 技术积分: 558
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-25 15:43
文章分类

全部博文(47)

文章存档

2016年(2)

2012年(10)

2011年(13)

2010年(1)

2009年(19)

2008年(2)

分类: 数据库开发技术

2016-03-02 23:22:56

BerkeleyDB这些年来, 加入了不少新的重大特性,但因为提供的是英文文档,而中文的示例一般写于这些特性之前,所以这些特性很少为人所知. 本文在此作一个简单介绍.

1 数据库分片

以前BerkeleyDB对一个数据库(DB, 相当于关系数据库的一个表)而言,只能存在一个物理文件中. 大约在版本4.8的时候, BerkeleyDB加入了数据库分片的功能, 允许将一个数据库的数据存放在多个分片中, 每个分片可以在文件系统中的不同位置. 通过此功能, 可以将一个数据库的数据分散在多个磁盘中, 利用多盘并发I/O(比如RAID10)的能力, 大大改善多核(或多CPU)多磁盘系统的性能.

分片的设置函数为:

点击(此处)折叠或打开

  1. int DB->set_partition(DB * db, u_int32_t parts, DBT *keys,
  2.     u_int32_t (*db_partition_fcn) (DB *db, DBT *key))
当前BerkeleyDB支持两种分片方式, 范围分片和Hash分片, 前者需要设置Keys(db_partition_fcn=NULL), 后者则需要设置db_partition_fcn(keys=NULL), 含义很明显, 不需累述.

BerkeleyDB通过以下函数来指定分片的位置

点击(此处)折叠或打开

  1. int DB->set_partition_dirs(DB *db, const char **dirs);
数据放置以Round-Robin的方式进行, 所以当目录数少于分片数时, 部分目录可能存在两个甚至多个分片.

当前不足的在于, 现在的分片是固定的, 无法自动扩展. 扩展需要自己写程序来移动数据.

2 大块数据存放


以前, 当在BerkeleyDB中存入的某些数据很大时(比如超过一个Page), BerkeleyDB会创建overflow page来存放这些数据. 当存放诸如视频或者音频,图片等数据时, 一个数据会被分为很多page, 散布在数据库中. 这有两个问题: 1 读回数据很麻烦, 读一个数据需要访问很多的Page, 哪怕是只读很小一部分, 带来的性能开销也很大; 插入也很复杂, 需要按Page大小(比page小一点, 因为page需要一部分header信息)来切开数据, 而后申请页面来存放, 直至放完. 更新数据也只能通过先删除后插入的方式进行; 2 占用表空间, 当前一个表支持2**32个页, 而这种大数据一个就能占据很多也. 结果可能导致数据库能存放的记录不多. 所以应用在存放大数据时, 一般只能走曲线途径, 即自己创建一个文件, 读写文件, 而后将文件名存入BerkeleyDB.

大约在6.0/6.1的时候, BerkeleyDB加入了对BLOB的支持, 允许通过一些设置,将大的数据直接存放为外部文件, 而BerkeleyDB负责文件的存放位置, 负责对文件进行操作,以及将文件同步到其他机器(replication).

相关主要函数有:

点击(此处)折叠或打开

  1. int DB_ENV->set_blob_threshold(DB_ENV *dbenv, u_int32_t bytes, u_int32_t flags);

  2. int DB->set_blob_threshold(DB *db, u_int32_t bytes, u_int32_t flags);

  3. int DBC->db_stream(DBC *dbc, DB_STREAM **dbs, u_int32_t flags);
  4. int DB_STREAM->read(DB_STREAM *dbs, DBT *data, db_off_t offset,
  5.      u_int32_t size, u_int32_t flags);
  6. int DB_STREAM->write(DB_STREAM *dbs, DBT *data, db_off_t offset, u_int32_t flags);

默认情况下, 外部文件存放在DB_ENV所在目录的子目录中(__b1), 但也可以通过DB_ENV->set_blob_dir, 以及DB->set_blob_dir来修改. 文件并不是平铺开来的, 而是按照一定的目录层次组织的, 避免一个文件夹下的文件数目膨胀.

3 DB_HEAP存取方法


无论是使用DB_BTREE/DB_RECNO还是DB_HASH等方式, 当存放数据时都可能会碰到节点分裂或者桶分裂(hash)的情形, 而此对性能影响很大. 而且无论是HASH还是BTREE, 存取速度都有一定的限制. 而新提供的DB_HEAP访问方式, 则改善了存取速度, 当然, 访问便利性也下降了. 应用一般需要通过DB_HEAP和其他方式结合才行.

DB_HEAP的工作方式是, 当要存放数据时, 根据所存放数据的大小,寻找空闲空间, 而后将数据存入, 返回一个DB_HEAP_RID告知数据的位置. 类似于malloc在Heap存储区获得空间的方式. DB_HEAP_RID包含page和page内偏移, 寻找数据时, 根据先前获得的DB_HEAP_RID可以非常快的定位到数据(物理位置), 而后获得数据. 此方法可以获得很高的数据插入和查询性能, 尤其适合日志类几乎不需要修改,但需要查询的数据. 目前有些应用将DB_QUEUE和DB_HEAP结合起来, 利用DB_QUEUE存放DB_HEAP_RID(因为定长), 这种方式结合了DB_QUEUE(记录级索引,定长记录,操作很快)和DB_HEAP的优势(可存放不定长记录). 还有一些用法是使用DB_HEAP存放原始数据, 而在数据上用DB_BTREE和DB_HASH来建立二级索引, 所有的查找都是用二级索引.

我的另一篇文章有一些简单的使用DB_HEAP的例子: http://blog.chinaunix.net/uid-20738531-id-2010948.html
阅读(1029) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~