命名键与数字键 - mongo

Posted

技术标签:

【中文标题】命名键与数字键 - mongo【英文标题】:named keys vs numerical keys - mongo 【发布时间】:2014-01-27 13:22:26 【问题描述】:

假设我们有一个 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) 而不是 (key, value, expiration)。以下是stats() 的输出:http://pastebin.com/tTt7VzwQ

【问题讨论】:

可能重复:***.com/questions/12790861/… @heinob 该问题中接受的答案与我的测试不符。 能否请您提供您的测试策略? (和 db.foo.stats() 输出) @xlembouras 将该信息编辑为问题。 【参考方案1】:

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

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

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

他们匹配每个统计数据。

我会说这比短字段名称与长字段名称大小相同更幸运。

您确定两者之间的数据是相同的,只是一个具有短字段名称和一个具有长字段名称?

我真的看不出expiration2 的大小在物理上是如何可能的,我可以看到key0 的字节数可能相对相同。

【讨论】:

数据是一样的。我只是用长字段名制作了集合中的数据。复制它。然后重命名新集合中的键,修复并压缩集合,然后运行统计信息。 @ConnorTumbleson 我必须承认这很奇怪。【参考方案2】:

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

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)); 

统计数据确实有很大差异(我删除了一些不相关的输出字段):

> db.int.stats();

    "ns" : "test.int",
    "count" : 1000,
    "size" : 9395008,
    "avgObjSize" : 9395,
    "storageSize" : 11182080,
    "numExtents" : 6,
    "lastExtentSize" : 8388608

> db.string.stats();

    "ns" : "test.string",
    "count" : 1000,
    "size" : 32098752,
    "avgObjSize" : 32098,
    "storageSize" : 37797888,
    "numExtents" : 8,
    "lastExtentSize" : 15290368

要解释您看到的小文档大小,我们可以参考 Mathias Stearn 的 storage internals presentation,特别是 slide #25。每条记录(例如本例中的文档)对于记录长度、范围和下一个/上一个指针都有 16 字节的开销。除此之外,文档的最小有效负载为 32 字节。因此,即使我们用非常小的文档填充集合:

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

统计数据将显示平均文档大小为 48:

> db.foo.stats()

    "ns" : "test.foo",
    "count" : 1000,
    "size" : 48032,
    "avgObjSize" : 48,
    "storageSize" : 172032,
    "numExtents" : 3,
    "lastExtentSize" : 131072

当文档有效负载超过 32 字节时,power-of-two 分配就会启动,因此您仍然可能会看到以圆形块分配的文档。在我的一些测试中,我注意到 112 是常见的平均尺寸 (96 + 16)。

【讨论】:

【参考方案3】:

我的第一个想法是他们已经实现了字段名称的压缩或标记化,但 issue 似乎仍未解决(截至 2014 年 1 月)。由于padding,它们的大小可能相同。出于性能原因,您集合中的文档会被填充,因此它们通常可以在原地调整大小而无需移动。您可以尝试compacting 没有任何填充的集合,看看您现在是否看到了不同。

【讨论】:

嗯。压实后大小相同。我将在我的测试和控制中添加更多文档。也许它太小了,无法进行任何比较。

以上是关于命名键与数字键 - mongo的主要内容,如果未能解决你的问题,请参考以下文章

mongo复制数据库和表

使用 Pig 从 Mongo 读取未命名的字符串数组

是否可以重命名 PyMongo 中 Mongo 查询输出中的字段?

是否可以在 mongo 的组聚合后重命名 _id 字段?

使用字符串分区键与整数分区键的 Hive/Impala 性能

文件夹重命名出现非法字符文件