Монго многопольный фильтр запросов и сортировки - оптимизация - PullRequest
0 голосов
/ 10 апреля 2019

У меня есть коллекция записей, среди которых есть primary_id (уникальный), вторичный_ид, поля состояния. Идентификаторы представляют собой буквенно-цифровые поля (например, «ABCD0000»), а статус - числовой (1 - 5). Один из часто используемых запросов - это фильтрация по id (равенство или диапазон) и статусу.

Примеры:

  1. записей, где primary_id между 'ABCD0000' - 'ABCN0000' и статусом 2 или 3, сортировка по primary_id.
  2. записывает, где вторичный_ид между 'ABCD0000' - 'ABCD0000' и статусом 2 или 3, сортировка по primary_id (или вторичному_id, если это поможет).

Статус в фильтре в основном будет (статус в (2,3)).

Первоначально у нас был один индекс для каждого из полей. Но запрос истекает, когда диапазон большой. Я попытался добавить несколько индексов (одиночных и составных) и разными способами написать фильтр, но не смог добиться достойной производительности. Теперь у меня есть эти индексы:

[
{primary_id: 1},
{secondary_id: 1},
{status: 1},
{primary_id: 1, status: 1},
{status: 1, primary_id: 1},
{status: 1, secondary_id: 1}
]

Этот запрос (с или без сортировки по primary_id)

{ $and: [ 
{ primary_id: { $gte: 'ABCD0000' } }, 
{ primary_id: { $lte: 'ABCN0000' } }, 
{status: { $in: [2,3] } } 
] }

используйте следующий план:

...
"winningPlan" : {
    "stage" : "FETCH",
    "filter" : {
            "status" : {
                    "$in" : [
                            2,
                            3
                    ]
            }
    },
    "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
                    "primary_id" : 1
            },
            "indexName" : "primary_idx",
            "isMultiKey" : false,
            "multiKeyPaths" : {
                    "primary_id" : [ ]
            },
            "isUnique" : true,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 2,
            "direction" : "forward",
            "indexBounds" : {
                    "primary_id" : [
                            "[\"ABCD0000\", \"ABCN0000\"]"
                    ]
            }
    }
},

Итак, кажется, что шаг FETCH занимает много времени, если количество возвращаемых строк велико. Удивительно, что при выполнении начальных тестов состояния составной индекс primary_id иногда выбирался как выигрышный план, и это было очень быстро (несколько секунд). Но по какой-то причине Монго его больше не выбирал. Я думаю, когда запрос должен быть отсортирован по primary_id, этот составной индекс не будет выбран, как я понял из документов Mongo

Если в запросе не указано условие равенства для префикса индекса, который предшествует или перекрывается со спецификацией сортировки, операция не будет эффективно использовать индекс.

Я пытался изменить запрос, как показано ниже, но он все еще не оптимизирован

{$or: [
{ $and: [ { primary_id: { $gte: 'ABCD0000' } }, { primary_id: { $lte: 'ABCN0000' } }, { status: 2 } ]},
{ $and: [ { primary_id: { $gte: 'ABCD0000' } }, { primary_id: { $lte: 'ABCN0000' } }, { status: 3 } ]}
]}

Какие-либо предложения о том, что будет лучшей стратегией индексирования или запроса?

1 Ответ

0 голосов
/ 07 июля 2019

Я бы попробовал с 2 индексами

primary_id, status и second_id, status.

Если тайм-аут все еще происходит, можете ли вы увеличить значение тайм-аута запроса? - учитывая большой набор данных, из которого вы пытаетесь прочитать.

Если эти индексы не помогают и ожидается хорошее время отклика, вам следует обратить внимание на аппаратные ограничения - достаточно ли подходит ваше оборудование (прочитайте размер рабочего набора mongodb). Либо увеличьте масштаб сервера / оборудования, либо посмотрите на сегрегацию, если производительность действительно вызывает беспокойство, а размер ваших данных будет расти.

ИЛИ - сохраняйте состояния 2 и 3 в отдельных коллекциях, чтобы уменьшить «размер рабочего набора» при запросе к ним.

...