1

我正在尽我所能优化数据库查找。据我了解,我的目标应该是针对唯一阶段是 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"=>"FETCH", "filter"=>{"soft_deleted_at"=>{"$eq"=>nil}},,它基本上是手动过滤我的日期字段的空值。我希望这已经在部分索引中并且不需要更多过滤......我错了吗?

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

4

1 回答 1

2

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

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

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

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

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

于 2019-03-04T15:57:44.913 回答