DocumentDB 子查询的性能是否足以执行 RDMS 样式连接?
Do DocumentDB Subqueries Perform Well Enough to do RDMS Style Joins?
DocumentDB 有它的优势。我认为大多数人会同意在文档之间创建关联并不是这些优势之一。
据我所知,常见的策略是尽可能保持数据非规范化,并在 原始 发生变化时围绕更新非规范化数据自定义逻辑。
但是,如果您需要在某些地方对数据进行标准化怎么办?假设我有 People 和 IceCreamFlavors。 Person 有一个 FavorityIceCreamFlavor
,它是 IceCreamFlavor 的 id。
据我所知,如果我需要为这个人获取 IceCreamFlavor,我将需要 运行 第二次查询来获取 IceCreamFlavor。
(单个集合 documentdb)
SELECT * FROM c c.id = "person-1"
{
"firstName": "John",
"lastname": "Doe",
"favorityIceCreamFlavor": "icecream-4"
}
获取 IceCreamFlavor-
select * From c WHERE c.id = "icecream-4"
{
"name": "Chocolate"
}
组合对象-
{
"firstName": "John",
"lastname": "Doe",
"favorityIceCreamFlavor": {
"name": "Chocolate"
}
}
显然不理想,但如果我正在查看个人资料,这还不是最糟糕的。此外,利用这种 风格 的文档存储 (documentdb),我可以创建存储过程,这样我就可以在服务器端执行此子查询。
但是如果我是管理员并且我想查看我的所有用户和他们最喜欢的冰淇淋怎么办?
这看起来像是个问题。看起来我必须执行 11 个子查询才能获取每个用户的冰淇淋口味。
这可能只是文档存储无法有效处理的问题。但我正在做那个假设——我不知道 documentdb 是如何在幕后工作的。
我是否应该担心 documentdb 在存储过程中对此处的每条记录进行查询?
DocumentDB 子查询的性能是否足以执行 RDMS 样式连接?
数据库需要执行两次查询才能完成连接。现在它们都可以在缓存中,或者只是索引,或者在某些情况下是整个操作。此外,该工作是在同一内存 space 中完成的,并且非常接近数据,因此吞吐量限制不会发挥作用。
DocumentDB/CosmosDB 如果您可以在存储过程中执行这两个查询,那么它的功能非常接近。只有当两个集合都在同一个分区中并且它们可以在 sproc 超时之前完成时(在大型数据库上检索 5K 到 20K 文档之间发生),你才能这样做,但是如果你可以使用存储过程,那么你就在相同的内存 space 并且非常接近数据。 SQL 连接和 DocumentDB/CosmosDB sproc 中的两次往返之间的延迟差异将是最小的,在包含 100k 文档的数据库上只有一位数毫秒,据我估计,您的查询只提取了 100 个文档。
我应该提到使用 sprocs 进行查询的其他一些缺点:1) 它可能会消耗更多的 RU,具体取决于连接逻辑的复杂性,以及 2) Sprocs 独立执行,这会限制并发并降低整体系统的吞吐量。另一方面,即使其他不太强的一致性模型之一对非存储过程查询有效,您也可以获得 ACID 一致性保证。
如果由于上述原因而无法使用存储过程,则需要在编写第二个查询之前通过网络将数据拉回第一个查询。在这种情况下,您将 运行 陷入吞吐量限制和额外延迟。多少取决于很多参数。在与保存数据的 DocumentDB/CosmosDB 分区相同的数据中心使用应用程序服务器可以将这种情况降到最低,但即使这样仍然会受到惩罚。视情况而定,可能会有毫秒差异,但会产生影响。如果第一轮就必须离开数据中心,然后再组成第二轮,那效果就更大了。
每个应用程序都是不同的,但对于典型的 OLTP 流量,我总是能够获得我需要的 DocumentDB 性能。即使是繁重的分析负载也可以工作,特别是如果您谨慎选择分区键以获得足够的并行性。我建议您通过一个接近您预期的最终产品的简单实验来尝试一下,看看效果如何。
希望这对您有所帮助。
DocumentDB 有它的优势。我认为大多数人会同意在文档之间创建关联并不是这些优势之一。
据我所知,常见的策略是尽可能保持数据非规范化,并在 原始 发生变化时围绕更新非规范化数据自定义逻辑。
但是,如果您需要在某些地方对数据进行标准化怎么办?假设我有 People 和 IceCreamFlavors。 Person 有一个 FavorityIceCreamFlavor
,它是 IceCreamFlavor 的 id。
据我所知,如果我需要为这个人获取 IceCreamFlavor,我将需要 运行 第二次查询来获取 IceCreamFlavor。
(单个集合 documentdb)
SELECT * FROM c c.id = "person-1"
{
"firstName": "John",
"lastname": "Doe",
"favorityIceCreamFlavor": "icecream-4"
}
获取 IceCreamFlavor-
select * From c WHERE c.id = "icecream-4"
{
"name": "Chocolate"
}
组合对象-
{
"firstName": "John",
"lastname": "Doe",
"favorityIceCreamFlavor": {
"name": "Chocolate"
}
}
显然不理想,但如果我正在查看个人资料,这还不是最糟糕的。此外,利用这种 风格 的文档存储 (documentdb),我可以创建存储过程,这样我就可以在服务器端执行此子查询。
但是如果我是管理员并且我想查看我的所有用户和他们最喜欢的冰淇淋怎么办?
这看起来像是个问题。看起来我必须执行 11 个子查询才能获取每个用户的冰淇淋口味。
这可能只是文档存储无法有效处理的问题。但我正在做那个假设——我不知道 documentdb 是如何在幕后工作的。
我是否应该担心 documentdb 在存储过程中对此处的每条记录进行查询?
DocumentDB 子查询的性能是否足以执行 RDMS 样式连接?
数据库需要执行两次查询才能完成连接。现在它们都可以在缓存中,或者只是索引,或者在某些情况下是整个操作。此外,该工作是在同一内存 space 中完成的,并且非常接近数据,因此吞吐量限制不会发挥作用。
DocumentDB/CosmosDB 如果您可以在存储过程中执行这两个查询,那么它的功能非常接近。只有当两个集合都在同一个分区中并且它们可以在 sproc 超时之前完成时(在大型数据库上检索 5K 到 20K 文档之间发生),你才能这样做,但是如果你可以使用存储过程,那么你就在相同的内存 space 并且非常接近数据。 SQL 连接和 DocumentDB/CosmosDB sproc 中的两次往返之间的延迟差异将是最小的,在包含 100k 文档的数据库上只有一位数毫秒,据我估计,您的查询只提取了 100 个文档。
我应该提到使用 sprocs 进行查询的其他一些缺点:1) 它可能会消耗更多的 RU,具体取决于连接逻辑的复杂性,以及 2) Sprocs 独立执行,这会限制并发并降低整体系统的吞吐量。另一方面,即使其他不太强的一致性模型之一对非存储过程查询有效,您也可以获得 ACID 一致性保证。
如果由于上述原因而无法使用存储过程,则需要在编写第二个查询之前通过网络将数据拉回第一个查询。在这种情况下,您将 运行 陷入吞吐量限制和额外延迟。多少取决于很多参数。在与保存数据的 DocumentDB/CosmosDB 分区相同的数据中心使用应用程序服务器可以将这种情况降到最低,但即使这样仍然会受到惩罚。视情况而定,可能会有毫秒差异,但会产生影响。如果第一轮就必须离开数据中心,然后再组成第二轮,那效果就更大了。
每个应用程序都是不同的,但对于典型的 OLTP 流量,我总是能够获得我需要的 DocumentDB 性能。即使是繁重的分析负载也可以工作,特别是如果您谨慎选择分区键以获得足够的并行性。我建议您通过一个接近您预期的最终产品的简单实验来尝试一下,看看效果如何。
希望这对您有所帮助。