1

我仍然习惯于使用无模式的面向文档的数据库,并且我想知道关于应用程序模型中的模式设计的普遍接受的做法是什么。

具体来说,我想知道在像这样保存到 mongodb 时,在应用程序模型中使用强制模式是否是一种好习惯:

{
    _id: "foobar",
    name: "John"
    billing: {
        address: "8237 Landeau Lane",
        city: "Eden Prairie",
        state: "MN",
        postal: null
    }
    balance: null,
    last_activity: null
}

而不是只存储这样使用的字段:

{
    _id: "foobar",
    name: "John"
    billing: {
        address: "8237 Landeau Lane",
        city: "Eden Prairie",
        state: "MN"
    }
}

前者是我喜欢的自我描述,而后者对模型模式的可变性不做任何假设。

我喜欢第一个选项,因为它可以很容易地一目了然地看到模型使用了哪些字段,但当前未指定,但如果我想添加,更新每个文档以反映新的架构设计似乎很麻烦一个额外的字段,例如favorite_color.

大多数资深 mongodb 用户如何处理这个问题?

4

2 回答 2

4

我建议第二种方法。

  1. 如果您查看源代码中的实体类,您总是可以看到预期的结构。还是您使用动态语言,并且不创建实体?
  2. 您可以为每条记录节省大量空间,因为您不必存储空列名。这在小型收藏中可能并不昂贵。但总的来说,有数百万条记录,我什至会缩短字段的名称。
  3. 正如你已经提到的。通过指定可选的列名,您可以创建一个模式,如果您想遵循该模式,则必须在添加新字段时更新所有现有记录。对于大型数据库来说,这又是一个坏主意。

无论如何,这一切都会降低您的数据库大小。如果您的目标不是很多 GB 或 TB 的数据,那么这两种方法都可以。但是,如果您预测您的数据库可能会变得非常大,我会做任何事情来减少大小。为列名花费 30-40% 的存储空间是个坏主意。

于 2013-01-24T11:45:59.530 回答
2

我更喜欢第一个选项,它更容易在应用程序中编码,并且需要更少的状态持有者和函数来理解事情应该如何工作。

至于随着时间的推移添加一个新字段,您不需要像在 SQL 中那样更新所有记录以支持这个新字段,您需要做的就是将新字段写入您的模型应用程序端并支持该字段,null如果它不是从 MongoDB 返回的。

一个很好的例子是 PHP。

我一user开始只有一个领域的一类,name

class User{
    public $name;
}

6 个月后,我想添加 60,000 个用户,比如说,address. 我所做的就是将该变量添加到我的应用程序模型中:

class User{
    public $name;
    public $address = array();
}

现在,这与向 SQL 中添加新null字段完全一样,无需实际按需将其添加到每一行。

这是一个非常被动的设计,不要更新你不需要的东西。如果该行被使用,它将被更新,如果没有,那么谁在乎。

所以最终你的行实际上变成了选项 1 和 2 之间的混合和匹配,但它实际上是一个反应选项 1。

编辑

在存储方面,您还必须考虑文档的预分配和移动。

假设现在设置的记录的数量仅为文档的三分之一,但突然间,从用户更新包含所有字段的文档开始,您现在从文档的移动中获得了额外的碎片。

通常,当您定义这样的模式时,您正在定义一个最终会增长并在大多数情况下应用于该用户的模式(很像 SQL 模式)。

需要考虑到这一点,即使存储在短期内可能会降低,但由于该碎片,它可能会导致碎片和查询缓慢,并且由于现在面临的问题,您很容易发现自己不得不运行compacts 或s。repairDb

我应该提一下,我上面提到的这两个功能都不是为了定期运行而设计的,并且在生产环境中运行时会对它们造成严重的性能问题。

因此,真正使用上面的结构,您不需要在所有文档中添加新字段,从长远来看,您很可能会减少移动和问题。

您可以通过使用 2 大小填充的力量来解决持续增长的文档的性能问题,但是这是集合范围的,这意味着即使您完全填充的文档也将使用至少两倍于以前的空间,并且您的小文档可能会用作在填充因子为1.

又名你失去了空间,而不是获得它。

于 2013-01-24T11:20:49.393 回答