BerkeleyDB 多索引查詢

2021-09-06 12:12:22 字數 3913 閱讀 5969

由於效能原因,我們打算將關係型資料庫轉移到記憶體資料庫中;在記憶體資料庫產品的選型中,我們確定的候選物件有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 ;

void second()

/** getname -- 從第乙個庫的鍵值對中提取第二個庫的key(即 last name)

*/int getname(db *secondary, const dbt *pkey, const dbt *pdata, dbt *skey)

插入資料

從開發者的角度來看,插入資料與第二個索引資料庫無關,直接操作第乙個資料庫中即可:

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 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》

posted by: 大cc | 26sep,2013

部落格:blog.me115.com

微博:

MySQL多索引查詢選擇

mysql選擇索引 引入 我們知道我們乙個表裡面可以有多個索引的,那麼我們查詢資料的時候不指定索引,mysql就會幫我們自動選擇。既然是mysql程式幫我們自動選擇的那麼會不會有問題的呢?答案是會的,mysql的優化器也有bug,有時候選擇的索引並不是最優的。案例1假如一張表有10w的資料,有id主...

es 多索引聯合查詢 HBase二級索引設計思想

1為什麼需要建立二級索引 hbase對於多條件組合查詢這種應用場景是非常不佔優勢的,甚至可以說就是其短板,一般情況下,我們有兩種方式查詢hbase中的資料 所以這時候我們就需要用建立二級索引的方法來解決這個問題 2二級索引原理 如上圖所示,hbase表中的字段為rowkey,age,username...

聯合索引(多列索引)

聯合索引是指對錶上的多個列進行索引,聯合索引也是一棵b 樹,不同的是聯合索引的鍵值數量不是1,而是大於等於2.最左匹配原則 假定上圖聯合索引的為 a,b 聯合索引也是一棵b 樹,不同的是b 樹在對索引a排序的基礎上,對索引b排序。所以資料按照 1,1 1,2 順序排放。對於selete from t...