出于性能原因,我们正在将数据库从MySQL迁移到MongoDB,并考虑将什么用于MongoDB文档的ID。我们正在讨论使用ObjectIDs,它是MongoDB的默认设置,还是使用UUID(这是我们迄今为止在MySQL中使用过的)。到目前为止,我们必须支持以下任何选项的论点如下:
的ObjectID: ObjectID是MongoDB的默认值,我假设(虽然我不确定)这是有原因的,这意味着我希望MongoDB可以比UUID更有效地处理它们,或者有其他理由选择它们。我还发现this stackoverflow answer提到ObjectIDs的使用使得索引更有效率,但是对于这个"更高效的"是
的UUID: 我们支持使用UUID的基本论点(并且它是非常重要的)是它们几乎可以通过任何数据库以这种或那种方式得到支持。这意味着如果在某种程度上我们决定从任何原因切换到MongoDB,我们已经有一个API,它根据ID从DB中检索文档,因为ID可以继续,所以这个API的客户端没有任何变化。完全一样。如果我们使用ObjectID,我不确定如何将它们迁移到另一个数据库。
有没有人对这些选项中的一个是否比另一个更好有什么见解?为什么?您是否曾在MongoDB中使用过UUID而不是ObjectIDs,如果是,您遇到的优势/问题是什么?
答案 0 :(得分:34)
MongoDB的_id
字段可以包含您想要的任何值,只要您可以保证它对于集合是唯一的。当您的数据已经具有自然键时,没有理由不使用它来代替自动生成的ObjectID。
提供ObjectID作为安全时间生成自己的唯一键的合理默认解决方案(并阻止初学者尝试复制SQL AUTO INCREMENT
,这在分布式数据库中是一个坏主意。)
如果不使用ObjectID,您还会错过另一个便利功能:ObjectID在生成时还包含一个unix时间戳,并且许多驱动程序提供了一个提取它并将其转换为日期的功能。这有时会使单独的create-date
字段变得多余。
但如果您不关心,则可以将您的UUID用作_id
字段。
答案 1 :(得分:9)
我认为这是个好主意,Mongo也是如此。他们将UUID列为the _id
field的常用选项之一。
注意事项:
应对其他一些答案:
ObjectID()
一样使用Mongo Shell中的UUID()
function;将字符串转换为等效的BSON对象。0x04
进行编码。)UUID()
中的内置功能仅生成v4(随机)UUID,因此,要利用此功能,您需要依靠应用或Mongo驱动程序来创建ID。答案 2 :(得分:6)
考虑每种情况下您将存储的数据量。
MongoDB ObjectID的大小为12个字节,打包用于存储,其部分按性能组织(即首先存储时间戳,这是一个逻辑排序标准)。
相反,标准UUID是36个字节,包含短划线,通常存储为字符串。此外,即使您删除非数字字符并打算以数字方式存储,您仍必须满足其“indexy”部分(基于时间戳的UUID v1部分)位于UUID的中间,并且不会t很适合排序。有studies完成,允许高性能的UUID存储,我甚至写了Node.js library来协助管理。
如果您打算使用UUID,请考虑重新组织它以获得最佳索引和排序;否则你可能会遇到一个表演墙。
答案 3 :(得分:1)
在我遇到同样问题的时候,我发现这些Benchmarks。 它们基本上表明使用Guid而不是ObjectId会导致索引性能下降。
我会建议您自定义基准来模仿您的特定现实生活场景并查看数字的外观,不能100%依赖通用基准测试。
答案 4 :(得分:1)
我们必须小心区分MongoDB插入事物的成本与首先产生事物的成本 plus 相对于有效负载大小的成本。以下是一个小的矩阵,显示了生成_id
的方法,该方法与可选的额外字节有效负载的大小交叉。测试仅使用javascript,在MacBook Pro本地主机上使用100个批次中的insertMany
进行了100,000次插入,没有进行任何事务以尝试消除网络,聊天和其他因素。还进行了两次批处理= 1的运行,只是为了突出显着差异。
Method
A : Simple int: _id:0, _id:1, ...
B : ObjectId _id:ObjectId("5e0e6a804888946fa61a1976"), ...
C : Simple string: _id:"A0", _id:"A1", ...
D : UUID length string _id:"9575edcc-cb70-4d63-97ed-ee5d624de87b0", ...
(but not actually
generated by UUID()
E : Real generated UUID _id: UUID("35992974-21ea-4f61-b715-2dfaed663b73"), ...
(stored UUID() object)
F : Real generated UUID _id: "6b16f733-ff24-4172-83f9-e4f96ace6775"
(stored as string, e.g.
UUID().toString().substr(6,36)
Time in milliseconds to perform 100,000 inserts on fresh (empty) collection.
Extra M E T H O D (Batch = 100)
Payload A B C D E F % drop A to F
-------- ---- ---- ---- ---- ---- ---- ------------
None 2379 2386 2418 2492 3472 4267 80%
512 2934 2928 3048 3128 4151 4870 66%
1024 3249 3309 3375 3390 4847 5237 61%
2048 3953 3832 3987 4342 5448 5888 49%
4096 6299 6343 6199 6449 7634 8640 37%
8192 9716 9292 9397 10816 11212 11321 16%
Extra M E T H O D (Batch = 1)
Payload A B C D E F % drop A to F
-------- ----- ----- ----- ----- ----- -----
None 48006 48419 49136 48757 50649 51280 6.8%
1024 50986 50894 49383 49373 51200 51821 1.2%
这是一项快速的测试,但是似乎很明显,基本字符串和整数与_id
的速度大致相同,但是实际上生成一个UUID会增加时间-特别是如果您使用字符串UUID()
对象的版本,例如UUID().toString().substr(6,36)
还值得注意的是,构建ObjectId
的速度似乎很快。
答案 5 :(得分:0)
过去几周我一直在考虑这个问题。我只是发现 ObjectId 和 UUID 都是独一无二的。事实上,在集合级别,无论使用什么类型,都不能有重复的 _id。一些答案谈到了插入性能。重要的是它与插入性能无关,它需要索引性能。这需要根据您将用于索引 _ids 的内存大小来计算。我们知道 ObjectId 是 12 个字节,而 UUID 是 36 个字节。它表示,对于相同数量的索引,如果您使用 UUID 而不是 ObjectId,您将需要 2 倍的内存空间。
所以从这个角度来看,在 mongodb 中最好使用 ObjectId 而不是 UUID。