Mongodb:在Web URL上创建唯一索引是一个好主意吗?

3

我的文档长这样:

{"url": "http://some-random-url.com/path/to/article"
"likes": 10
}

该url需要是唯一的。在url上创建一个唯一索引是个好主意吗?由于URL可以很长,这会导致更大的索引大小、更多的内存占用和更慢的整体性能。从url生成哈希值(我考虑使用 murmur3)并在其上创建唯一索引代替是否是个好注意。我假设碰撞的机会非常低,如此描述:https://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed

有人看到这种方法的任何缺点吗?新文档将如下所示(索引名为u_hash而不是url):

{"url": "http://some-random-url.com/path/to/article"
"likes": 10
"u_hash": "<murmur3 hash of url>"
}

更新

我不会在url上进行正则表达式查询。将只进行完整的URL查找。我更关心此查找的性能,因为我相信它也将被mongodb内部用于维护唯一索引,从而影响写入性能(+较长的索引)。此外,我的理解是,mongobd对于长文本索引的表现不佳,因为它并非为此目的而设计。虽然可能取决于该索引是否适合RAM。有什么建议吗?


我目前也遇到了同样的问题,你能找出如何以哈希格式存储URL吗?我的URL长度在1000-3000个字符之间,虽然唯一但仍会导致索引过大的错误。 - PirateApp
1
我的URL没有这么长,所以我最终在URL上创建了一个索引。如果你的大多数URL都超过1000个字符,你可能想尝试使用文本索引:https://docs.mongodb.com/manual/core/index-text/。现在不确定它的性能如何,所以你需要自己试一下。另一种方法是在保存之前缩短URL,通过实现一个自己的缩短程序或使用第三方程序来缩短URL,然后对缩短后的URL进行索引。 - amit_saxena
你有没有想到最好的解决方案?目前URL正在影响我的性能。 - Burf2000
这个问题已经太久远,我都记不清了,但我猜我们在URL索引方面没有遇到任何问题,尽管我认为我们的URL并不是很长(可能是内部URL)。如果你的URL太长,索引占用了所有的内存,那么你可以尝试使用URL缩短方法或者对哈希进行索引。 - amit_saxena
3个回答

2
我想进一步解释@AlexRyan的答案。虽然他总体上是正确的,但对于这种用例,有些事情需要考虑。
首先,我们必须区分唯一索引和_id字段。
当您的用例需要URL唯一时,必须有一个唯一索引。我们必须决定是使用URL本身还是其哈希值。哈希本身不会帮助搜索,因为MongoDB中保存的哈希总和将被视为字符串。它可以节省空间(URL可能比其哈希值短),从而减少所需的索引内存。但是,这样做会取消在索引中搜索URL部分的可能性,例如:
db.collection.find({url:{$regex:/stackoverflow/}})

通过在url上创建唯一索引,此查询将使用索引,速度相对较快。如果没有这个(唯一)索引,则该查询将导致较慢的集合扫描。
此外,在每次查询、更新或插入之前都创建哈希值并不能使这些操作更快。
这就意味着,在节省一些RAM的同时,创建哈希校验和及其上的唯一索引可能会使查询实际字段变得极慢,并且需要每次创建哈希值。在URL和它的哈希值上都建立索引是没有意义的。
现在来回答是否有必要用URL作为_id。由于URL通常天生具有独特性(它们应该返回相同的内容),而点赞等则与该独特性相关联,我倾向于将URL用作id。由于您需要在_id上建立唯一索引,因此它在这里有两个目的:您拥有文档的id,确保URL的唯一性,并且 - 如果您使用URL的自然表示方式,则甚至可以以高效的方式查询它。

已经对问题进行了更新。我更关心完整的url查找和添加的读写性能,与为哈希表执行此操作相比(生成哈希表的速度非常快- SO链接详细介绍了用于非加密目的的快速哈希算法)。不过还是感谢您的回答。 - amit_saxena
无论速度有多快:哈希值并保存它比_不_哈希并保存它要慢。你可能节省的几个字节并不是问题所在。磁盘延迟是一个更大的问题,除非你有极长的URL(块大小的更高因子,这意味着URL远远超过4kB)。 - Markus W Mahlberg
关于“哈希本身不能帮助搜索,因为MongoDB中保存在字段中的哈希值将被视为字符串”的问题:哈希保存在索引中,并引用相应文档,而不是文档本身。它也可以像任何索引一样帮助搜索,只是它只能满足相等条件,而不能满足范围条件,因为哈希不能保留值的顺序。 - wdberkeley
@wdberkely:这是针对哈希索引的吧?不是针对手动哈希字段上的索引,或者我有什么地方理解错误吗? - Markus W Mahlberg

1
在url上使用唯一索引。
db.interwebs.ensureIndex({ "url" : 1}, { "unique" : 1 })

而不是散列索引。在MongoDB中,散列索引用于散列分片键,而不是唯一约束条件。从散列索引文档中可以了解到,
散列索引支持使用散列分片键对集合进行分片。使用散列分片键对集合进行分片可以确保数据更均匀地分布。
并且,
您不能创建具有散列索引字段的复合索引,也不能在散列索引上指定唯一约束条件。
如果url需要是唯一的,并且您将使用它来查找文档,则绝对值得在url上拥有唯一索引。如果您想将url用作文档的主键,可以将url值存储在_id字段中。这个字段通常是由驱动程序生成的ObjectId,但它可以是任何你喜欢的值。在MongoDB集合中,_id总是有一个唯一索引,因此您可以免费获得唯一索引。

我目前也遇到了同样的问题,我的URL长度在1000-3000个字符之间,但是它们是100%唯一的。我该如何对它们进行哈希处理?MongoDB是否有内置机制来哈希URL,还是我需要使用第三方库?你有什么建议吗? - PirateApp

0

我认为答案是“这取决于情况”。

选择没有实际含义的键可能会在未来避免痛苦。如果您决定更改它,但有许多外键引用它,这一点尤其正确。

大多数数据库管理系统都提供了一种生成唯一ID的方法。 在Oracle中,您可以使用序列。 在MySQL中,您可以在定义表本身时使用AUTO_INCREMENT。

Mongodb分配文档唯一ID的方式与关系型数据库不同。他们使用ObjectIDs来实现此目的。

关于ObjectIDs的有趣之处之一是它们由驱动程序生成。 由于用于生成它们的算法,即使您拥有大量应用程序和数据库服务器的集群,它们也保证是唯一的。

您可以在此处了解更多信息: http://docs.mongodb.org/manual/reference/object-id/

已经进行了大量工程工作以确保ObjectIds唯一。 除非有非常好的理由不使用它们,否则我默认使用它们。 到目前为止,我还没有找到不使用它们的真正好理由。


我从未质疑过mongo ids的有用性或有效性。在我的特定情况下,URL需要是唯一的,并且我需要快速查找数百万个文档中的URL。因此,重点在于是否应该直接在url上创建索引还是在url的哈希值上创建索引。 - amit_saxena
_id 不必是 ObjectId。它们可以是任何东西(但在一个 mongod 中,对于所有文档都必须是唯一的)。 - wdberkeley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接