MongoDB和部分索引:在空日期过滤时避免过滤阶段

Posted

技术标签:

【中文标题】MongoDB和部分索引:在空日期过滤时避免过滤阶段【英文标题】:MongoDB & Partial indexes : Avoid filtering stage when filtering on null date 【发布时间】:2019-07-25 21:49:00 【问题描述】:

我正在尽我所能优化数据库查找。据我了解,我的目标应该是针对唯一阶段是 IXScan 的获胜计划。但是我有一个包含日期键的字段,似乎我无法构建一个复合索引,在过滤“空”日期值时能够直接查找文档。

我的过滤查询如下

    "$and":[
      "published":true,
      "soft_deleted_at":null, # <-- this one's a date field, I need null values
      "another_filter":false,
      "yet_another_filter":false
    ]`

我尝试构建一个与该查询完全对应的部分索引(为了也节省一些索引内存,因为我知道我永远不必显示例如软删除的文档)

(请注意,代码是用 Ruby 编写的,但是使用 Mongoid 可以毫无问题地转换为 MongoDB 语言)

index(
  
    published: 1,
    another_filter: 1,
    soft_deleted_at: 1,
    yet_another_filter: 1,
  ,
  
    background: true,
    name: 'Visible in search engine partial index',
    partial_filter_expression: 
      '$and': [
        "published":true,
        "soft_deleted_at":null,
        "another_filter":false,
        "yet_another_filter":false
      ]
    
  
)

除了soft_deleted_at 过滤器之外,这似乎运作良好,因为我的获胜计划看起来像

=> "stage"=>"FETCH",
 "filter"=>"soft_deleted_at"=>"$eq"=>nil,
 "inputStage"=>
  "stage"=>"IXSCAN",
   "keyPattern"=>"published"=>1, "another_filter"=>1, "soft_deleted_at"=>1, "yet_another_filter"=>1,
   "indexName"=>"Visible in search engine partial index",
   "isMultiKey"=>false,
   "multiKeyPaths"=>"published"=>[], "another_filter"=>[], "soft_deleted_at"=>[], "yet_another_filter"=>[],
   "isUnique"=>false,
   "isSparse"=>false,
   "isPartial"=>true,
   "indexVersion"=>2,
   "direction"=>"forward",
   "indexBounds"=>
    "published"=>["[true, true]"], "another_filter"=>["[false, false]"], "soft_deleted_at"=>["[null, null]"], "yet_another_filter"=>["[false, false]"]

所以在这里我有这个额外的阶段"stage"=&gt;"FETCH", "filter"=&gt;"soft_deleted_at"=&gt;"$eq"=&gt;nil,,它基本上是手动过滤我的日期字段的空值。我希望这已经在部分索引中并且不需要更多过滤......我错了吗?

有什么方法可以避免这个额外的过滤阶段吗?

【问题讨论】:

【参考方案1】:

有什么方法可以避免这个额外的过滤阶段吗?

不,没有。 (至少,不是您当前的数据架构)

Mongo 为不存在(null & undefined)创建索引与存在有点不同。它实际上使用了soft_deleted_at 索引(请注意,它在[null, null] 的范围内进行过滤,但这也在获取soft_deleted_atundefined 的值。它无法使用索引来过滤掉这些值,所以它必须这样做filter 步骤。

虽然一般来说,最好避免过滤阶段,但这似乎不会导致成本高昂。您不会获取任何额外的文档,因此唯一的成本是检查获取的文档中的单个字段。

另一种方法是添加一个类似false 的值并以此进行搜索。如果您有一个像 deleted 这样的字段,它对每个文档都是真或假(并且您与 soft_deleted_at 同时更新)您的查询计划将不包括 filter 阶段。

【讨论】:

以上是关于MongoDB和部分索引:在空日期过滤时避免过滤阶段的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Kettle 中过滤 Mongodb INPUT 时传递变量

在 mongodb python 上根据日期上传和过滤年龄

日期和时间过滤器在 find() 操作中工作正常,但 $match 与 mongodb 中的聚合出现问题

如何按月份和年份输入过滤具有日期时间索引的数据框?熊猫

具有特定条件计数的 Mongodb 聚合并按输出投影的日期范围过滤不能按预期工作

Cassandra 使用二级索引按日期过滤