Соответствие MongoDB для документов и вложенных документов, что использовать в качестве индексов? - PullRequest
2 голосов
/ 17 марта 2020

У меня есть много документов, выглядящих так:

[{
        "title": "Luxe [daagse] [verzorging] @ Egypte! Incl. vluchten, transfers & 4* ho",
        "price": 433,
        "automatic": false,
        "destination": "5d26fc92f72acc7a0b19f2c4",
        "date": "2020-01-19T00:00:00.000+00:00",
        "days": 8,
        "arrival_airport": "5d1f5b407ec7385fa2963623",
        "departure_airport": "5d1f5adb7ec7385fa2963307",
        "board_type": "5d08e1dfff6c4f13f6db1e6c"
    },
    {
        "title": "Luxe [daagse] [verzorging] @ Egypte! Incl. vluchten, transfers & 4* ho",
        "automatic": true,
        "destination": "5d26fc92f72acc7a0b19f2c4",
        "prices": [{
                "price": 433,
                "date_from": "2020-01-19T00:00:00.000+00:00",
                "date_to": "2020-01-28T00:00:00.000+00:00",
                "day_count": 8,
                "arrival_airport": "5d1f5b407ec7385fa2963623",
                "departure_airport": "5d1f5adb7ec7385fa2963307",
                "board_type": "5d08e1dfff6c4f13f6db1e6c"
            },
            {
                "price": 899,
                "date_from": "2020-04-19T00:00:00.000+00:00",
                "date_to": "2020-04-28T00:00:00.000+00:00",
                "day_count": 19,
                "arrival_airport": "5d1f5b407ec7385fa2963623",
                "departure_airport": "5d1f5adb7ec7385fa2963307",
                "board_type": "5d08e1dfff6c4f13f6db1e6c"
            }
        ]
    }
]

Как видите, автоматические c сделки имеют несколько цен (может быть много, между 1000 и 4000) и не имеют Доступны исходные поля.

Теперь мне нужно искать в исходном документе, а также во вложенных документах, чтобы найти совпадение.

Это объединение, которое я использую для поиска по документам:

[{
    "$match": {
        "destination": {
            "$in": ["5d26fc9af72acc7a0b19f313"]
        }
    }
}, {
    "$match": {
        "$or": [{
            "prices": {
                "$elemMatch": {
                    "price": {
                        "$lte": 1500,
                        "$gte": 400
                    },
                    "date_to": {
                        "$lte": "2020-04-30T22:00:00.000Z"
                    },
                    "date_from": {
                        "$gte": "2020-03-31T22:00:00.000Z"
                    },
                    "board_type": {
                        "$in": ["5d08e1bfff6c4f13f6db1e68"]
                    }
                }
            }
        }, {
            "price": {
                "$lte": 1500,
                "$gte": 400
            },
            "date": {
                "$lte": "2020-04-30T22:00:00.000Z",
                "$gte": "2020-03-31T22:00:00.000Z"
            },
            "board_type": {
                "$in": ["5d08e1bfff6c4f13f6db1e68"]
            }
        }]
    }
}, {
    "$limit": 20
}]

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

Ответы [ 2 ]

3 голосов
/ 17 марта 2020

С понедельника go $ или документы:

При оценке предложений в выражении $ или $ MongoDB выполняет сканирование коллекции или, если все предложения поддерживаются индексами, MongoDB выполняет сканирование индексов. То есть, чтобы MongoDB использовал индексы для вычисления выражения $ или, все выражения в выражении $ или должны поддерживаться индексами. В противном случае MongoDB выполнит сканирование коллекции.

Так что, чтобы избежать сканирования коллекции в этом конвейере, вам нужно создать составной индекс , содержащий оба price и prices поля.

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

Мне кажется, что индекс вы хочу создать выглядит примерно так:

{destination: 1, date: 1, board_type: 1, price: 1, prices: 1}
2 голосов
/ 17 марта 2020

Составной индекс, включающий поля фильтра совпадений, необходим для быстрой агрегации. В запросах агрегации наличие стадии $match на ранней стадии конвейера (предпочтительно первой стадии) использует индексы, если таковые определены в полях фильтра. В размещенном запросе это так, и определение индексов необходимо для быстрого запроса. Но индекс по каким полям?

Индекс будет составной индекс ; т. е. индекс по нескольким полям критериев запроса. Префикс индекса начинается с поля destination. Остальные поля индекса должны быть определены. Каковы остальные поля?

Большинство этих полей находятся в полях вложенного документа массива prices - price, date_from, date_to и board_type. Также есть поле date из основного документа. Какие из этих полей необходимо использовать в составном индексе?

Определение индексов для элементов массива (или полей поддокументов в массиве) создает множество ключей индекса. Это означает много памяти и для использования индекса памяти (или оперативной памяти). Это важное соображение. Индексы для элементов массива называются индексами с несколькими ключами . Для правильного использования индекса документы коллекции и индекс, используемый запросом (вместе именуемый рабочий набор ), должны помещаться в ОЗУ.

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

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

{ destination: 1, fld1: 1, fld2: 1, ... }

fld1, fld2, ..., будут полями вложенного документа массива prices и / или поле date. Я думаю, что только один набор полей даты может быть использован с индексом. Примером индекса может быть один из них:

{ destination: 1, date: 1,  "prices.price": 1, "prices.board_type": 1}
{ destination: 1, "prices.price": 1, "prices.date_from": 1, "prices.date_to": 1, "prices.board_type": 1}

Обратите внимание на ключи индекса order и необходимость из price, date_from, date_to и board_type определяется на основе двух основных факторов - требования к рабочему набору и избирательности запроса - это важно.

ПРИМЕЧАНИЯ : для небольшого выборочного набора данных с аналогичной структурой показали использование составного индекса с основным полем destination и двумя полями из prices (одно с условием равенства и одно с условием диапазона). План запроса с использованием explain показал IXSCAN (сканирование индекса) в составном индексе, и использование индекса наверняка улучшит производительность запроса.

...