为面向文档的数据库设计记录键-最佳实践



我们的团队已经开始开发一个由CouchbaseDB支持的应用程序;对于我们每个人来说,这是第一次使用无SQL数据库。

我们已经开始定义我们的实体,并采用了Couchbase手册建议的使用"类型"前缀的做法:

Entity "A":
key: a#123
Entity "B":
key: b#123

但我们意识到,我们在选择创建复合文档密钥的策略时感到困惑。我们经常使用计数器,他们需要自己的文档。我们的钥匙变得很复杂:

Daily counter "x" for entity "A":
key: cntrx#a#123-20140117

我们已经考虑了不同的方法,但在这个问题上我们仍然是新手,我们想征求一些建议。

层次键有什么好处吗?任何人都可以分享他们定义非琐碎密钥的最佳实践吗?

在我们的项目中,我们以如下所述的方式使用了层次键:键的第一部分类似于RDBMS中的表名:users-表示"表格">

然后每个用户都有自己的id,例如:

users:1-"代表一个用户">

我们使用了":",因为我认为它看起来比其他分隔符更好。您可以使用任何您喜欢的分隔符。

如果你想使用像前面例子中的id那样的顺序索引,你需要从某个键中获取它们,所以:

users:counter-保存"最后一个用户id"的密钥(其作用类似于自动递增)

如果你需要为用户帐户存储一些"分段",你可以存储它:

users:<user's id>:subsection

更复杂的示例

users:1:avatars:1:url-意味着通过这个密钥我们将获得用户1的化身url,但如果用户想存储许多化身,他们将进入users:1:avatars:X:url,其中X将是users:1:avatars:counter密钥的值。

我们对所有只存储一个值(JSON甚至二进制数据)的文档都使用了这种策略。

因此,就你的例子而言,我会选择:

a:123-20140117:counter——这意味着我们有一个名为"a"的表(用RDBMS语言来说),在表"a"中,我们有id为(或其他)"123-20140117"的记录,该记录具有字段"cntrx"。

UPD:关于密钥大小。其实这并不重要。是的,键的大小是有限的,但有很多方法可以减少它。其中之一是使用哈希,但我认为这是一种糟糕的方法,因为键会很长,消耗更多的内存。在我们的项目中,我们为memcached bucket使用了"短"键。我们有一个枚举(也可以存储在couchbase中),它表示人类可以理解的密钥名称及其缩写值。

示例:我们有一些记录:拥有30张以上照片的用户列表。所以我们有一个键值对:

usersByPhotosCount - k:ubpc:{0}

对于30张照片,密钥将是CCD_ 11。

但最好只在生产上进行这样的优化。在开发过程中,最好在应用程序和数据库中有可理解的密钥(即,您可以创建两组k-v对:正常用于开发,缩短和模糊用于生产,并根据您的环境加载它们)。

关于您的问题,我有几点建议。

总体

Nosql就像它听起来一样,它需要一种与以前设计好的SQL数据库截然不同的心态。例如,nosql数据库基本上就是一个大的散列映射。因此,尽管在你的钥匙里放一些想法可能是件好事(例如,把它们弄小),但请记住,它们只是访问你的文档的一种手段。除非让它们以某种方式看起来有一些特定的优势,否则它们根本不需要有任何意义——通常总是需要首先进行主查找。举个例子,你的用户多久会知道他们需要要求";b#123";直接导航到您的应用程序?我唯一认为这是有利的地方是在用户名或用户可能知道的其他数据中。

复合键

虽然CB手册可能建议复合密钥是一个好主意(它们很可能适用于简单的数据库结构),但一般来说,密钥大小应该尽可能小。密钥最多限制为256个字节。所有密钥都必须存储在RAM中,因此密钥中的数据越多,可用于其余数据的数据就越少。相反,我建议在文档中创建一个类型字段,然后使用视图拉出特定类型的对象(或按类型索引对象)。这最终会给你更大的灵活性。

计数器

你对计数器的解释相当模糊,所以我假设你将它们用作自动递增键。我建议,这里的方法需要改变,以摆脱计数器。我对数据库中的所有密钥使用唯一标识符。当我使用复合密钥时,这是因为密钥本身很重要(例如,在受修订控制的文档中,我使用文档id+文档保存日期的复合密钥,以确保它是唯一的)。即使您有几百万(甚至数十亿)个对象,您也可以使用12字节的GUID来确保文档ID的唯一性。这样可以防止应用程序在需要保存新记录时出现严重的瓶颈。

最新更新