MongoDB и частичные индексы: избегайте стадии фильтрации при фильтрации по нулевой дате - PullRequest
0 голосов
/ 04 марта 2019

Я пытаюсь оптимизировать поиск в БД как можно лучше.Из того, что я понимаю, моя цель должна заключаться в том, чтобы нацелиться на выигрышный план, где единственным этапом является 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, но он без проблем переводит на язык MongoDB с использованием Mongoid)

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 Ответ

0 голосов
/ 04 марта 2019

Есть ли какой-нибудь способ, которым я могу избежать этой дополнительной стадии фильтрации?

Нет, нет.(По крайней мере, не с вашей текущей схемой данных)

Mongo создает индексы для небытия (null & undefined) немного иначе, чем существование.На самом деле он использует индекс soft_deleted_at (обратите внимание, что он фильтрует в диапазоне [null, null], но он также выбирает значения, где soft_deleted_at равен undefined. Он не может использовать индекс для фильтрации этих значенийтак что он должен сделать этот шаг filter.

Хотя в целом лучше избегать этапов фильтрации, это не похоже на случай, когда это будет дорогостоящим.любые дополнительные документы, поэтому единственной ценой является проверка выбранных документов для одного поля.

Альтернативой может быть добавление значения, такого как false, и поиск по нему. Если у вас есть поле, подобное deletedэто было либо истина, либо ложь для каждого документа (и который вы обновили одновременно с soft_deleted_at), ваш план запроса не будет включать этап filter.

...