我的文档如下:
{"url": "http://some-random-url.com/path/to/article"
"likes": 10
}
网址必须是唯一的。在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。有什么指针吗?
答案 0 :(得分:1)
我想扩展@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的自然表示 - 它甚至会可以有效地查询。
答案 1 :(得分:1)
在网址上使用唯一索引
db.interwebs.ensureIndex({ "url" : 1}, { "unique" : 1 })
而不是散列索引。 MongoDB中的散列索引用于散列分片键,而不用于唯一约束。来自hashed index docs,
散列索引支持使用散列分片键对集合进行分片。使用散列分片键对集合进行分片可确保更均匀的数据分发。
和
您可能无法创建具有散列索引字段的复合索引或在散列索引上指定唯一约束
如果url
需要是唯一的,并且您将使用它来查找文档,那么url
上的唯一索引绝对值得。如果要将url
用作文档的主键,可以将url
值存储在_id
字段中。该字段通常是驱动程序生成的ObjectId,但它可以是您喜欢的任何值。 MongoDB集合中的_id
始终有唯一索引,因此您可以“免费”获得唯一索引。
答案 2 :(得分:0)
我认为答案是&#34;它取决于&#34;。
选择没有嵌入真实世界意义的密钥可以为您节省未来的痛苦。如果您决定需要更改它但是有很多外键引用它,则尤其如此。
大多数数据库管理系统都为您提供了生成唯一ID的方法。 在Oracle中,您可以使用序列。 在MySQL中,您可以在定义表本身时使用AUTO_INCREMENT。
mongodb为文档分配唯一ID的方式与关系数据库中的方式不同。他们为此目的使用ObjectID。
ObjectID的一个有趣的事情是它们是由驱动程序生成的。 由于用于生成它们的算法,即使您有大量的应用程序和数据库服务器,它们也可以保证是唯一的。
您可以在此处了解有关他们的更多信息: http://docs.mongodb.org/manual/reference/object-id/
许多工程工作已经用于确保ObjectIds的唯一性。 我默认使用它们,除非有一个非常好的理由不这样做。 到目前为止,我还没有找到一个不使用它们的理由。