DocumentDB 索引性能/碎片
DocumentDB Index Performance / Fragmentation
我决定为我的文档实施以下 ID 策略,它将文档 "type" 与 ID 组合在一起:
doc.id = "docType_" + Guid.NewGuid().ToString("n");
// create document in collection
这会为我的文档生成如下 ID:
usr_19d17037ea7f41a9b20db1a90f71d30d
usr_89fe82c93b264076aa1b6e1fb4813aaf
usr_2aa58c1c970a4c5eaa206a755c1c7bf4
msg_ec43510732ae47a6a5d5f323b7461d68
msg_3b03ceeb7e06490d998c3e368b435851
通过对 ID 实施 RangeIndex
策略,我应该能够查询特定类型的集合。例如:
SELECT * FROM c WHERE STARTSWITH(c.id, 'usr_') AND ...
由于这是一个包含许多不同文档类型的 Web 应用程序,因此我的应用程序的许多查询将默认实现此 STARTSWITH
过滤器。
我主要关心的是在 ID 上使用随机 GUID 字符串。我知道在 SQL 服务器中,在聚集索引的主键上使用随机 GUID 时,我遇到了索引性能和碎片问题。
这里有类似的问题吗?似乎在 DocumentDB 中,管理索引的工作已经从您那里抽象出来了。顺序 ID 会更 ideal/performant 吗?
tl;dr:为类型和仅 GUID ID 使用单独的字段,并在两者上使用哈希索引。
根据您问题的性质,这个答案必然会有些自以为是。让我首先解决您最关心的问题,即影响性能的索引碎片。
DocumentDB 假定使用 GUID 和散列索引(与范围索引相反)非常适合通过 GUID 查找一个匹配的实体。另一方面,如果您想通过查看字符串的开头来查找一组文档,我怀疑使用范围索引可能会更高效。这假设 STARTSWITH 仅在与范围索引一起使用时进行了优化,但我不知道即使你有范围索引它也会被优化的事实。
我的建议是为类型和仅限 GUID 的 ID 使用单独的字段,并在两者上使用哈希索引。这给您带来的好处是,您可以放心,像您显示的那样的查询将具有高性能,并且将类型子句与其他参数组合在一起的查询也将能够使用至少一个索引。请注意,这种类型的散列索引(比如 2x 3 字节 = 6 bytes/document)的效率很高 space,所以不用担心需要其中两个。这两个组合应该比一个范围索引小得多,范围索引需要有足够的精度来覆盖你的类型+GUID 的整个长度。
除了已经讨论过的性能和 space 原因之外,我可以看到将类型与 GUID 组合的其他一些缺点:1) 尝试检索单个文档时(直接使用和作为外键查找的一部分),将 GUID 分开并使用散列索引将比在组合字段上使用范围索引更快且更 space 高效; 2) 将类型与 ID 相结合会使某些通常需要在以后完成的迁移变得非常复杂。假设您决定将用户分成作者和 reader 等。用户是其他文档类型(博客 post 作者,reader 评论等)中由用户 ID 引用的外键。如果该 ID 包含类型,那么您不仅需要更改用户文档以完成迁移,还需要查找和更改每个外键。如果这两个字段(GUID 和类型)是分开的,那么您只需要更改用户文档。敏捷软件工艺在很大程度上是关于做出在未来提供灵活性的决策。
至于顺序索引的使用,一般数据库(尤其是 NoSQL)的趋势是提供单调递增的顺序 ID 的复杂性大于 space-效率优势通过 GUID。如果您要坚持使用 DocumentDB,我建议您顺其自然并使用 GUID。
我决定为我的文档实施以下 ID 策略,它将文档 "type" 与 ID 组合在一起:
doc.id = "docType_" + Guid.NewGuid().ToString("n");
// create document in collection
这会为我的文档生成如下 ID:
usr_19d17037ea7f41a9b20db1a90f71d30d
usr_89fe82c93b264076aa1b6e1fb4813aaf
usr_2aa58c1c970a4c5eaa206a755c1c7bf4
msg_ec43510732ae47a6a5d5f323b7461d68
msg_3b03ceeb7e06490d998c3e368b435851
通过对 ID 实施 RangeIndex
策略,我应该能够查询特定类型的集合。例如:
SELECT * FROM c WHERE STARTSWITH(c.id, 'usr_') AND ...
由于这是一个包含许多不同文档类型的 Web 应用程序,因此我的应用程序的许多查询将默认实现此 STARTSWITH
过滤器。
我主要关心的是在 ID 上使用随机 GUID 字符串。我知道在 SQL 服务器中,在聚集索引的主键上使用随机 GUID 时,我遇到了索引性能和碎片问题。
这里有类似的问题吗?似乎在 DocumentDB 中,管理索引的工作已经从您那里抽象出来了。顺序 ID 会更 ideal/performant 吗?
tl;dr:为类型和仅 GUID ID 使用单独的字段,并在两者上使用哈希索引。
根据您问题的性质,这个答案必然会有些自以为是。让我首先解决您最关心的问题,即影响性能的索引碎片。
DocumentDB 假定使用 GUID 和散列索引(与范围索引相反)非常适合通过 GUID 查找一个匹配的实体。另一方面,如果您想通过查看字符串的开头来查找一组文档,我怀疑使用范围索引可能会更高效。这假设 STARTSWITH 仅在与范围索引一起使用时进行了优化,但我不知道即使你有范围索引它也会被优化的事实。
我的建议是为类型和仅限 GUID 的 ID 使用单独的字段,并在两者上使用哈希索引。这给您带来的好处是,您可以放心,像您显示的那样的查询将具有高性能,并且将类型子句与其他参数组合在一起的查询也将能够使用至少一个索引。请注意,这种类型的散列索引(比如 2x 3 字节 = 6 bytes/document)的效率很高 space,所以不用担心需要其中两个。这两个组合应该比一个范围索引小得多,范围索引需要有足够的精度来覆盖你的类型+GUID 的整个长度。
除了已经讨论过的性能和 space 原因之外,我可以看到将类型与 GUID 组合的其他一些缺点:1) 尝试检索单个文档时(直接使用和作为外键查找的一部分),将 GUID 分开并使用散列索引将比在组合字段上使用范围索引更快且更 space 高效; 2) 将类型与 ID 相结合会使某些通常需要在以后完成的迁移变得非常复杂。假设您决定将用户分成作者和 reader 等。用户是其他文档类型(博客 post 作者,reader 评论等)中由用户 ID 引用的外键。如果该 ID 包含类型,那么您不仅需要更改用户文档以完成迁移,还需要查找和更改每个外键。如果这两个字段(GUID 和类型)是分开的,那么您只需要更改用户文档。敏捷软件工艺在很大程度上是关于做出在未来提供灵活性的决策。
至于顺序索引的使用,一般数据库(尤其是 NoSQL)的趋势是提供单调递增的顺序 ID 的复杂性大于 space-效率优势通过 GUID。如果您要坚持使用 DocumentDB,我建议您顺其自然并使用 GUID。