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"=>"FETCH", "filter"=>"soft_deleted_at"=>"$eq"=>nil,
,它基本上是手动过滤我的日期字段的空值。我希望这已经在部分索引中并且不需要更多过滤......我错了吗?
有什么方法可以避免这个额外的过滤阶段吗?
【问题讨论】:
【参考方案1】:有什么方法可以避免这个额外的过滤阶段吗?
不,没有。 (至少,不是您当前的数据架构)
Mongo 为不存在(null & undefined)创建索引与存在有点不同。它实际上使用了soft_deleted_at
索引(请注意,它在[null, null]
的范围内进行过滤,但这也在获取soft_deleted_at
为undefined
的值。它无法使用索引来过滤掉这些值,所以它必须这样做filter
步骤。
虽然一般来说,最好避免过滤阶段,但这似乎不会导致成本高昂。您不会获取任何额外的文档,因此唯一的成本是检查获取的文档中的单个字段。
另一种方法是添加一个类似false
的值并以此进行搜索。如果您有一个像 deleted
这样的字段,它对每个文档都是真或假(并且您与 soft_deleted_at
同时更新)您的查询计划将不包括 filter
阶段。
【讨论】:
以上是关于MongoDB和部分索引:在空日期过滤时避免过滤阶段的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Kettle 中过滤 Mongodb INPUT 时传递变量
日期和时间过滤器在 find() 操作中工作正常,但 $match 与 mongodb 中的聚合出现问题