Key/Value 数据库的二级索引
Secondary Index on Key/Value database
比方说,我有像
这样的数据结构
type User struct {
UUid string
Username string
Email String
Password string
FirstName string
LastName string
}
我正在将 Users []User 存储到 levelDB 的 key/value 数据库中。唯一键将是 UUid,然后用户结构将根据此 UUID 进行编码和存储。
var network bytes.Buffer // Stand-in for a network connection
enc := gob.NewEncoder(&network)
err := enc.Encode(user)
if err != nil {
log.Println("Error in encoding gob")
return "", err
}
err = dbSession.DBSession.Put([]byte(user.UserID), network.Bytes(), nil)
由于所有条目的键都是唯一的 uuid,我想在电子邮件上创建二级索引,这样我就不必扫描数据库中存在的所有条目来查找与电子邮件对应的特定条目.
我做了什么:
我创建了一个名为 SIndex 的键,并在其中存储了一个 map[string][string] 数据结构,其中键是电子邮件,值是 uuid。每次有新条目进入时,此 Sindex 都会更新以适应新的 uuid 和电子邮件。
这是一个糟糕的方法:
因为随着数据的增长,需要把Sindex对应的整个map抓取并解码,如果email不存在,就在Sindex中添加一个新的key,编码后重新存回。
B 树更合适。
我的问题:在数据库本身存储二级索引数据是否正确,如果不是我应该使用什么策略来实现二级索引,我知道二级索引的选择受数据的影响很大但是有没有除了 B-Tree、HashMaps 之外,还有哪些开箱即用的索引算法?
Is it right to store secondary index data in the Database itself
是的,没关系。但正如 Jonas 在评论中指出的那样,您应该将电子邮件作为键,将 UUID 作为值。另一种选择是使用电子邮件作为数据库的密钥,而不是使用 UUID。这样您就不需要使用二级索引。
另一个更好的性能策略,你可以使用内存数据库,如Redis(或者LevelDB本身可以用来将数据存储在内存中)来存储二级索引(email作为键,UUID作为值) .
Are there any good out of box indexing algorithms other than B-Tree, HashMaps
反正B-Tree和HashMap是数据结构,不是算法。而您实际上所做的并不是使用 HashMap 进行索引,它只是将 HashMap 存储为您的键的值。索引通常取决于 DBMS 实现(我们只能从他们提供的选项中进行选择)。
所以,关于用于索引的数据结构,它是否好,真的取决于用例。例如,如果您需要进行范围搜索,您可以使用 B-Tree(大多数 DBMS 默认使用)、B+ 树(MySQL InnoDB 默认使用)和 Skip List(Redis 使用此数据其有序集的结构)。您可以阅读更多关于使用 Redis Sorted Set here 进行二级索引的信息。
对于您的情况,您只需将电子邮件存储为键,将 UUID 存储为值。 Hash Table 通常用于此。大多数 DBMS 使用这种数据结构来进行主键访问,时间复杂度仅为 O(1)。而且我相信 LevelDB 的实现也是基于这种数据结构的。
比方说,我有像
这样的数据结构 type User struct {
UUid string
Username string
Email String
Password string
FirstName string
LastName string
}
我正在将 Users []User 存储到 levelDB 的 key/value 数据库中。唯一键将是 UUid,然后用户结构将根据此 UUID 进行编码和存储。
var network bytes.Buffer // Stand-in for a network connection
enc := gob.NewEncoder(&network)
err := enc.Encode(user)
if err != nil {
log.Println("Error in encoding gob")
return "", err
}
err = dbSession.DBSession.Put([]byte(user.UserID), network.Bytes(), nil)
由于所有条目的键都是唯一的 uuid,我想在电子邮件上创建二级索引,这样我就不必扫描数据库中存在的所有条目来查找与电子邮件对应的特定条目.
我做了什么: 我创建了一个名为 SIndex 的键,并在其中存储了一个 map[string][string] 数据结构,其中键是电子邮件,值是 uuid。每次有新条目进入时,此 Sindex 都会更新以适应新的 uuid 和电子邮件。
这是一个糟糕的方法: 因为随着数据的增长,需要把Sindex对应的整个map抓取并解码,如果email不存在,就在Sindex中添加一个新的key,编码后重新存回。
B 树更合适。
我的问题:在数据库本身存储二级索引数据是否正确,如果不是我应该使用什么策略来实现二级索引,我知道二级索引的选择受数据的影响很大但是有没有除了 B-Tree、HashMaps 之外,还有哪些开箱即用的索引算法?
Is it right to store secondary index data in the Database itself
是的,没关系。但正如 Jonas 在评论中指出的那样,您应该将电子邮件作为键,将 UUID 作为值。另一种选择是使用电子邮件作为数据库的密钥,而不是使用 UUID。这样您就不需要使用二级索引。
另一个更好的性能策略,你可以使用内存数据库,如Redis(或者LevelDB本身可以用来将数据存储在内存中)来存储二级索引(email作为键,UUID作为值) .
Are there any good out of box indexing algorithms other than B-Tree, HashMaps
反正B-Tree和HashMap是数据结构,不是算法。而您实际上所做的并不是使用 HashMap 进行索引,它只是将 HashMap 存储为您的键的值。索引通常取决于 DBMS 实现(我们只能从他们提供的选项中进行选择)。
所以,关于用于索引的数据结构,它是否好,真的取决于用例。例如,如果您需要进行范围搜索,您可以使用 B-Tree(大多数 DBMS 默认使用)、B+ 树(MySQL InnoDB 默认使用)和 Skip List(Redis 使用此数据其有序集的结构)。您可以阅读更多关于使用 Redis Sorted Set here 进行二级索引的信息。
对于您的情况,您只需将电子邮件存储为键,将 UUID 存储为值。 Hash Table 通常用于此。大多数 DBMS 使用这种数据结构来进行主键访问,时间复杂度仅为 O(1)。而且我相信 LevelDB 的实现也是基于这种数据结构的。