`
colin115
  • 浏览: 41153 次
社区版块
存档分类
最新评论

BerkeleyDB 多索引查询

    博客分类:
  • C++
阅读更多

由于性能原因,我们打算将关系型数据库转移到内存数据库中;在内存数据库产品的选型中,我们确定的候选对象有Redis和Berkeley DB;

Redis查询效率不错,并且支持丰富的数据存储结构,但不支持多索引,这样对于比较复杂的sql移植可能会造成数据膨胀;Berkeley DB只支持简单的Key/Value, 但支持多索引查询,对我们目前的应用来说,移植起来更有优势;

 

下面我们看看,如何为DB建立二级索引;

还是用例子来说明:

一张表中记录学生的信息;每个学生有个唯一的ID,这个id通常就是表的主键;

现在,我们希望通过学生的last_name来查询,这就需要建立二级索引;

注:用词约定:

* 本文提到的“数据库”是指Berkeley DB的database,相当于关系数据库的一个表。

作为SQL的常用表:

CREATE TABLE students(student_id CHAR(4) NOT NULL,lastname CHAR(15),

firstname CHAR(15), PRIMARY KEY(student_id)); CREATE INDEX lname ON students(lastname);

在Berkeley DB中,就是定义为如下结构:

struct student_record {
    char student_id[4];
    char last_name[15];
    char first_name[15];
};

void second()
{
    DB *dbp, *sdbp;
    int ret;

    /* 创建/打开第一个数据库*/
    if ((ret = db_create(&dbp, dbenv, 0)) != 0)
        handle_error(ret);
    if ((ret = dbp->open(dbp, NULL,
        "students.db", NULL, DB_BTREE, DB_CREATE, 0600)) != 0)
        handle_error(ret);
    /* 打开第二个数据库,注意,需要申明这个库支持重复记录,因为学生的last_name不是唯一的,是可能重复的*/  
    if ((ret = db_create(&sdbp, dbenv, 0)) != 0)
        handle_error(ret);
    if ((ret = sdbp->set_flags(sdbp, DB_DUP | DB_DUPSORT)) != 0)
        handle_error(ret);
    if ((ret = sdbp->open(sdbp, NULL,
        "lastname.db", NULL, DB_BTREE, DB_CREATE, 0600)) != 0)
        handle_error(ret);

    /* 将二级个库关联到第一个库上. 注:getname是提取key函数*/
    if ((ret = dbp->associate(dbp, NULL, sdbp, getname, 0)) != 0)
        handle_error(ret);
}

/*
* getname -- 从第一个库的键值对中提取第二个库的key(即 last name)
*/
int getname(DB *secondary, const DBT *pkey, const DBT *pdata, DBT *skey)
{
    /*
     * 这里第二个key是数据的简单结构,所以并不需要做其它的工作,直接返回就完事。
     *  如果第二个key是需要从复杂记录中提取出来再组建,这个用户函数可能需要做分配空间和copy数据的工作;在这种情况下,对于第二个键的DBT结构需要设置 DB_DBT_APPMALLOC 标志位;*/
    memset(skey, 0, sizeof(DBT));
    skey->data = ((struct student_record *)pdata->data)->last_name;
    skey->size = sizeof(((struct student_record *)pdata->data)->last_name);
    return (0);
}

 

插入数据

从开发者的角度来看,插入数据与第二个索引数据库无关,直接操作第一个数据库中即可:

struct student_record s;
DBT data, key;
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
memset(&s, 0, sizeof(struct student_record));
key.data = "WC42";
key.size = 4;
memcpy(&s.student_id, "WC42", sizeof(s.student_id));
memcpy(&s.last_name, "Churchill      ", sizeof(s.last_name));
memcpy(&s.first_name, "Winston        ", sizeof(s.first_name));
data.data = &s;
data.size = sizeof(s);
if ((ret = dbp->put(dbp, txn, &key, &data, 0)) != 0)
    handle_error(ret);

 

删除数据

删除数据可以通过第一个索引(student_id)来删除,也可以通过第二个索引(last_name)来删除,无论使用哪个索引删除,被删除的都是第一个库中的真实数据;

eg: 使用第一个索引删除:

BT key;
memset(&key, 0, sizeof(DBT));
key.data = "WC42";
key.size = 4;
if ((ret = dbp->del(dbp, txn, &key, 0)) != 0)
    handle_error(ret);

 

eg:使用二级个索引删除:

 

DBT skey;
memset(&skey, 0, sizeof(DBT));
skey.data = "Churchill      ";
skey.size = 15;
if ((ret = sdbp->del(sdbp, txn, &skey, 0)) != 0)
    handle_error(ret);

 

这里需要注意的是,第二个索引并非唯一性索引,所以可能对应多条数据,执行删除操作,将删除所有对应的数据;

 

查询数据

使用第一个索引查询数据,使用DB->get();

使用第二个索引查询数据,可使用DB->pget() 或者 DB->pget()

两者的区别就是,如果使用DB->pget() ,则会将查询到的数据对应的第一个索引key同时返回;(DBC->pget()也是这样)

这里给出两者的函数原型:

#include <db_cxx.h>
int Db::get(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags);
int Db::pget(DbTxn *txnid, Dbt *key, Dbt *pkey, Dbt *data, u_int32_t flags); 
pkey即第一索引的key;

eg:
DBT data, pkey, skey;
memset(&skey, 0, sizeof(DBT));
memset(&pkey, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
skey.data = "Churchill      ";
skey.size = 15;
if ((ret = sdbp->pget(sdbp, txn, &skey, &pkey, &data, 0)) != 0)
    handle_error(ret);

 

错误处理

在DS或CDS上更新二级索引时,可能会产生以下错误:

• 0

• DB_BUFFER_SMALL

• DB_NOTFOUND

• DB_KEYEMPTY

• DB_KEYEXIST

为了防止这些错误,在索引更新后,最好立刻删除这个二级索引,然后重建;

注意:DB_RUNRECOVERY 和 DB_PAGE_NOTFOUND属于严重级错误,一般不会发生;

如果Berkeley DB返回了这类错误,需要首先检查数据库的完整性(使用DB->verify()),确认没问题后再重建索引;

 

总结

一旦调用DB->associate() 将两个索引库关联起来,二级索引就成为第一数据库的另一个入口;

所有的更新操作都会影响与其关联的索引库;

在二级索引上,游标的操作函数都可正常使用;

需要指出的是,对于插入操作,BDB禁止通过二级索引来插入数据,因为那样的话,就没有方法为第一数据库指明主索引。应用程序,应该在第一个数据库上使用DB->put() or DBC->put()来插入数据;

可以对建立任意多个二级索引,BDB中对这方面没有限制;只要内存大小允许,以及文件描述符够用,理论上对于一个数据库可以建立任意多个二级索引;当然,索引不是越多越好,在数据更新时,索引的更新也是不小的代价;所以,设计阶段,对于索引的建立,需要精心的设计一二;

如果发现二级索引失效了,应该通过调用DB->remove()将其删除,同时,再调用一次DB->associate() 方法来生成新的索引;

如果二级索引库不再需要了,需要先关闭数据库句柄,DB->close(),再将其删除:DB->remove();

关闭主索引库句柄时,会自动关闭所以与其关联的二级索引句柄;

 

更多参考

《Reference Guide for Berkeley DB》

http://docs.oracle.com/cd/E17076_03/html/index.html

 

Posted by: 大CC | 26SEP,2013

博客:blog.me115.com

微博:新浪微博

0
3
分享到:
评论

相关推荐

    Berkeley DB4.8以上各版本

    2. **性能优化**:这个版本可能包含了对查询性能的优化,比如更快的索引查找和数据读取。通过改进内部算法和数据结构,Berkeley DB可以更快地处理大量数据。 3. **空间效率**:Berkeley DB通常关注内存和磁盘空间的...

    Berkeley DB数据库最新版

    此外,通过合理的数据结构设计和索引策略,可以进一步提升查询效率。 **10. 系统资源** 由于BDB是轻量级数据库,它对系统资源的需求相对较低,尤其适合资源有限的环境。不过,这也意味着其功能可能没有大型关系型...

    BerkeleyDB测试程序

    4. **并发读取**:在多线程环境中并行执行读取操作,以测试BerkeleyDB的并发性能。 5. **性能分析**:收集上述测试的结果,计算平均读取时间、吞吐量等指标,对比不同操作和环境下的性能差异。 **性能优化** 在...

    Berkeley DB参考资料

    - **概念解释**:二级数据库是对主数据库的一个索引,用于提高查询效率。 - **应用场景**:快速查找、数据统计等。 - **3.2 创建二级数据库** - **创建流程**:首先创建主数据库,然后基于主数据库创建对应的二级...

    Berkeley DB C++编程入门教

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

    BerkeleyDB Manual C/C++

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

    Berkeley DB 读取样例

    在实际应用中,Berkeley DB提供了丰富的API来处理复杂的数据库操作,如事务处理、索引、复制等。例如,你可以通过开启事务来保证数据的一致性,使用索引来加速查询,或者利用复制功能实现数据冗余和高可用性。 总的...

    SQL 开发人员 Oracle Berkeley DB 指南

    主键在Berkeley DB中被称为“主索引键”,次键则对应于“次索引”。 首先,我们需要创建数据库环境。在SQL中,你可以使用`CREATE DATABASE`语句。而在Berkeley DB中,你需要创建一个数据库环境,这是通过DB_ENV类型...

    Berkeley DB

    3. **多种访问方法**:除了基本的B树索引外,Berkeley DB还支持哈希表、固定记录长度和动态记录长度等多种访问方法,满足不同场景下的性能需求。 4. **内存映射**:Berkeley DB支持将数据库文件映射到进程的内存...

    SQLite和Berkeley DB对比资料收集

    Berkeley DB的体系结构也可以分成多个子系统,包括数据存储引擎、索引管理器、事务管理器等。 通过对比分析,我们可以了解到SQLite和Berkeley DB在不同的方面的优势和劣势。SQLite具有体积小、功能齐备、可移植性、...

    SQL开发与berkeleyDB

    尽管BerkeleyDB并非完全兼容SQL,但对于那些需要高性能查询的应用程序来说,BerkeleyDB提供了一种非常高效的选择。 #### 二、BerkeleyDB与SQL术语对照 为了更好地理解BerkeleyDB与SQL之间的关系,下面列出了一些...

    Berkeley DB文章集合

    3. **多版本并发控制(MVCC)**:Berkeley DB通过MVCC实现并发操作,允许多个读写操作同时进行,提高了系统的并行处理能力。 4. **内存数据库**:Berkeley DB允许数据完全驻留在内存中,极大地提高了读写速度,适用...

    db Oracle Berkeley DB

    Berkeley DB的设计理念是简单和快速,它不采用SQL作为查询语言,而是通过API直接与数据进行交互。这种设计使得Berkeley DB在处理大量小记录时表现出色,尤其是在需要事务处理和并发控制的场景下。它提供了多种数据...

    berkeley db xml说明手册

    2. **XML索引**: 通过使用XPath或XQuery表达式,Berkeley DB XML可以创建针对XML内容的索引,这极大地提高了查询速度,使得大数据集的检索变得高效。 3. **事务支持**: 基于Berkeley DB的核心,Berkeley DB XML提供...

    BerkeleyDB PDF

    ### Berkeley DB API Reference详解 #### 一、简介 Berkeley DB 是一款高性能的嵌入式数据库引擎,由 Sleepycat Software 开发,并于 2006 年被 Oracle 收购。它提供了多种访问方法,包括 B+树、哈希表、队列和...

    Berkeley_DB_m.rar_Berkeley_Berkeley DB

    Berkeley DB 提供了多种性能优化策略,如缓存机制、索引优化、并发控制等。通过合理配置,可以大大提高数据存取速度和系统吞吐量。 ### 7. 安全性与备份 Berkeley DB 支持数据加密,保障敏感信息的安全。同时,...

Global site tag (gtag.js) - Google Analytics