Mongodb 命名键与数字键-mongo

Mongodb 命名键与数字键-mongo,mongodb,Mongodb,假设我们有一个Mongo实例专门用于缓存。该集合只是以下内容的数组转储 _id key value expiration 然而,我们的项目团队中有人。存储为 _id 0 1 2 我们的后端(PHP)知道0=“key”,1=“value”,2=“expiration”。他说,“最好这样做,这样我们就不会在Mongo中的每一条记录中都存储一个长的键名。” 这对我来说本来是有意义的,因为每个文档都是独立存储的。然而,使用任何管理工具或试图在应用程序之外操纵数据几乎是不可能的。这就像看1和0一样。所

假设我们有一个Mongo实例专门用于缓存。该集合只是以下内容的数组转储

_id
key
value
expiration
然而,我们的项目团队中有人。存储为

_id
0
1
2
我们的后端(PHP)知道0=“key”,1=“value”,2=“expiration”。他说,“最好这样做,这样我们就不会在Mongo中的每一条记录中都存储一个长的键名。”

这对我来说本来是有意义的,因为每个文档都是独立存储的。然而,使用任何管理工具或试图在应用程序之外操纵数据几乎是不可能的。这就像看1和0一样。所以我出去测试这个

我制作了一个由命名键和数字组成的Mongo小集合。这样做之后。我在这两个数据库上都运行了
db.foo.stats()

他们匹配了所有的统计数据,所以我想我的问题是。如果我们有一个名为
VeryLongKeyDescriptiveText
的键,它存储在1000条记录中。这与存储
0
的物理大小以及相应的值是否相同?(我的测试结果是肯定的,但我不明白Mongo是怎么做到的)


我的测试是两个集合(控制和测试)。使用上述两个键值设置。每个集合当前有3个文档,包括一个名称、一些base64 loren ipsum文本和unix过期时间戳。两个集合具有相同的精确数据,但测试中的键除外,它们是(0,1,2)而不是(键、值、过期)。以下是这两个数据库的
stats()
输出:

我的第一个想法是,它们实现了字段名的压缩或标记化,但这似乎仍然没有解决(截至2014年1月)。它们可能是相同的大小,因为它们的形状不同。由于性能原因,集合中的文档会被填充,因此它们通常可以在不需要移动的情况下就地调整大小。您可以在不添加任何填充的情况下尝试该集合,看看现在是否看到了差异

的确,这两种观点之间的数据库大小差异通常是不成比例的,事实上,在1000条记录中,短字段名和长字段名之间的差异可能只有1MB

有时,如果您始终使用长字段名,并且它们相当长,您将开始看到真正的问题

此问题的识别也可以与文档内容大小联系起来。我的意思是,如果您的文档已经很大,那么您不会注意到太多的更改

他们匹配了每一个数据

我想说,这比短字段名与长字段名大小相同更幸运

除了一个字段名较短,另一个字段名较长之外,您确定这两个字段之间的数据相同吗


我真的看不出
expiration
的大小与
2
的大小在物理上是如何可能的,我可以看到
key
0
的字节数是如何相对相同的。

如果扩展测试用例以创建更大的文档,存储差异会变得更明显。考虑以下事项:

function createIntFields(j) {
  var document = {};
  for (i = 0; i < j; i++) {
    document[i] = i;
  }
  return document;
}

function createStringFields(j) {
  var document = {};
  for (i = 0; i < j; i++) {
    document["thisIsAVeryLongFieldNamePrefix" + i] = i;
  }
  return document;
}

db.int.drop();
for (i = 0; i < 1000; i++) { db.int.insert(createIntFields(i)); }

db.string.drop();
for (i = 0; i < 1000; i++) { db.string.insert(createStringFields(i)); }
为了解释您在小文档中看到的内容,我们可以特别参考Mathias Stearn的。每个记录(例如本例中的文档)都有16个字节的记录长度、范围和下一个/上一个指针开销。除此之外,文档的最小有效负载是32字节。因此,即使我们用非常小的文档填充集合:

db.foo.drop();
for (i = 0; i < 1000; i++) { db.foo.insert({_id:i}); }

当一个文档负载超过32字节时,分配就开始了,所以您仍然可以看到以圆形块分配的文档。在我的一些测试中,我注意到112是一个普通的平均大小(96+16)。

可能重复:@heinob该问题的公认答案与我的测试不一致。请提供您的测试策略好吗?(和db.foo.stats()输出)@xlembouras将该信息编辑成question.hm。压实后尺寸相同。我将向测试和控制添加更多文档。也许它太小了,无法进行任何比较。数据是一样的。我只是用长字段名创建集合中的数据。复制了它。然后重命名新集合中的密钥,修复并压缩集合,然后运行stats。@ConnorTumbleson我必须承认这是一个奇怪的问题。
db.foo.drop();
for (i = 0; i < 1000; i++) { db.foo.insert({_id:i}); }
> db.foo.stats()
{
    "ns" : "test.foo",
    "count" : 1000,
    "size" : 48032,
    "avgObjSize" : 48,
    "storageSize" : 172032,
    "numExtents" : 3,
    "lastExtentSize" : 131072
}