【问题标题】:Mongodb: Is it a good idea to create a unique index on web URLs?Mongodb:在 Web URL 上创建唯一索引是个好主意吗?
【发布时间】:2014-09-19 21:54:51
【问题描述】:

我的文档如下:

{"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。有什么指点吗?

【问题讨论】:

  • 我目前面临同样的问题,您是否能够弄清楚如何以散列格式存储网址?我的网址有 1000- 3000 个字符长,但独一无二,并且不断生成索引过大错误,
  • 我的 URL 没有这么长,我最终在 URL 上创建了一个索引。如果您的大多数 URL 都大于 1000 个字符,您可能需要尝试文本索引:docs.mongodb.com/manual/core/index-text。现在确定它的性能如何,因此您需要尝试一下。另一种方法可能是您在保存之前通过自己实现缩短器或使用第三方缩短 URL,然后将缩短的 URL 编入索引。
  • 你有没有想到什么是最好的,因为 URL 正在扼杀我的表现
  • 这个问题太老了,不记得了,但我想我们对 URL 的索引没有问题,尽管我认为我们的 URL 不是太长(可能是内部 URL)。如果您的 URL 太长并且索引占用了您所有的内存,那么您可以尝试使用 URL 缩短方法或索引哈希。

标签: ruby-on-rails ruby mongodb indexing mongoid


【解决方案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 的自然表示 - 它甚至是可查询的以一种有效的方式。

【讨论】:

  • 添加了问题的更新。我更关心完整 url 查找和添加的读/写性能,与对哈希进行比较时(生成速度非常快 - SO 链接包含有关用于非加密目的的快速哈希 alogos 的详细信息) .不过感谢您的回答。
  • 不管它有多快:散列一个值并保存它比 not 散列并保存它慢。您可能节省的几个字节并不是问题所在。磁盘延迟是一个更大的问题,除非你有非常长的 URL(块大小的一个更高的因素,这意味着 URL 比 4kB 长得多)。
  • Re“哈希本身对搜索没有帮助,因为保存在字段中的哈希总和将被 MongoDB 视为字符串”:哈希保存在索引中并引用相应的文件,而不是在文件上。它也有助于搜索,就像任何索引一样,除了它只能满足相等条件而不是范围条件,因为散列不保留值的顺序。
  • @wdberkely:那将是一个散列索引,对吧?不是手动散列字段上的索引,还是我在这里遗漏了什么?
【解决方案2】:

在 url 上使用唯一索引

db.interwebs.ensureIndex({ "url" : 1}, { "unique" : 1 })

而不是散列索引。 MongoDB 中的散列索引旨在用于散列分片键,而不是用于唯一约束。来自hashed index docs

散列索引支持使用散列分片键对集合进行分片。使用散列分片键对集合进行分片可确保数据分布更均匀。

您不得创建具有散列索引字段的复合索引或在散列索引上指定唯一约束

如果url 需要唯一并且您将使用它来查找文档,那么绝对值得在url 上使用唯一索引。如果您想使用url 作为文档的主键,您可以将url 值存储在_id 字段中。此字段通常是驱动程序生成的 ObjectId,但它可以是您喜欢的任何值。在 MongoDB 集合中,_id 上始终存在唯一索引,因此您可以“免费”获得唯一索引。

【讨论】:

  • 我目前有同样的问题,我的网址有 1000-3000 个字符长,但 100% 唯一,我该如何对它们进行哈希处理? mongodb 是否有一些内置机制来散列 url 或者我需要一个 3rd 方库?任何建议
【解决方案3】:

我认为答案是“视情况而定”。

选择其中嵌入了没有现实世界意义的键可能会在将来为您省去痛苦。如果您决定需要更改它但您有很多引用它的外键,则尤其如此。

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

mongodb 为文档分配唯一 ID 的方式与关系数据库不同。他们为此使用 ObjectID。

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

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

为了确保 ObjectId 的唯一性,我们进行了大量工程工作。 我默认使用它们,除非有很好的理由不这样做。 到目前为止,我还没有找到一个很好的理由不使用它们。

【讨论】:

  • 我从未质疑过 mongo id 的有用性或有效性。在我的特殊情况下,URL 需要是唯一的,我需要在数百万个文档中快速查找 URL。所以它更多地集中在我是否应该直接在 url 上创建索引,或者 url 的哈希。
  • _id 不必是 ObjectId。它们可以是任何东西(但对于一个 mongod 上的所有文档必须是唯一的)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-29
  • 2018-06-29
  • 2011-09-18
相关资源
最近更新 更多