使用离群值模式对数据进行分组
如果您的集合存储的文档大小和形状大致相同,则完全不同的文档(异常值)可能会导致常见查询出现性能问题。
考虑一个存储数组字段的集合。如果某个文档包含的数组元素比集合中的其他文档多得多,那么您可能需要在模式中以不同方式处理该文档。
使用异常值模式将不符合预期形状的文档与集合的其余文档隔离开来。您的模式仍保留所有同样的数据,但常用查询不受单个大文档的影响。
开始之前
在修改模式以处理异常值之前,请考虑异常值模式的利弊:
优点
异常值模式可提高常用查询的性能。返回典型文档的查询不需要同时返回大型异常文档。
离群值模式还能处理应用程序中的边缘情况。例如,如果应用程序通常显示数组中的 50 个结果,则不会有包含 2,000 个结果的文档,以免影响用户体验。
缺点
离群值模式需要更复杂的逻辑来处理更新。 如果您经常需要更新数据,则可能需要考虑其他模式设计模式。 有关详细信息,请参阅离群值更新。
关于此任务
考虑一个追踪图书销售的模式。集合中的典型文档如下所示:
db.sales.insertOne( { "_id": 1, "title": "Invisible Cities", "year": 1972, "author": "Italo Calvino", "customers_purchased": [ "user00", "user01", "user02" ] } )
customers_purchased
数组是无界数组,这意味着随着购买图书的客户数量增加,数组会变大。 对于大多数文档,这不是问题,因为商店对特定书籍的销量期望不会很高。
假设一本新的热门图书引发大量购买。当前的模式设计会导致文档臃肿,从而对性能产生负面影响。要解决此问题,请对没有典型销售量的文档实施异常值模式。
步骤
结果
异常值模式可防止非典型文档影响查询性能。生成的模式避免了集合中出现大型文档,同时维护了完整的销售列表。
考虑一个应用程序页面,它显示有关图书和购买该图书的所有用户的信息。实施异常值模式后,页面会快速显示大多数图书(典型文档)的信息。
对于热门图书(异常值),应用程序会在 extra_sales
集合中对 book_id
执行额外的查询。若要提高此查询的性能,可以在 book_id
字段上创建索引。
异常值更新
您需要以不同于典型文档的方式处理异常文档的更新。用于执行更新的逻辑取决于您的模式设计。
要对上述模式的异常值执行更新,请实现以下应用程序逻辑:
检查正在更新的文档是否已将
has_extras
设置为true
。如果
has_extras
缺失或为false
,则将新增购买添加到sales
集合中。如果生成的
customers_purchased
数组包含的元素超过 50 个,则将has_extras
设置为true
。
如果
has_extras
为true
,则将新增购买添加到相应book_id
的sales_extras
集合中。