Оптимизация запроса MongoDB для доктрины - PullRequest
1 голос
/ 15 марта 2012

Этот запрос занимает очень много времени в моем приложении.База данных содержит около 2 миллионов записей.

    $results = $queryBuilder
        ->field('extra.targetPlayerId')->exists(FALSE)
        ->field('permission')->equals('public')
        ->field('time')->gt($weekEndTime) // variable is timestamp
        ->field('time')->lte($startTime) // variable is timestamp
        ->map(
            'function() {
                var total = 0;
                if (this.comments) {
                    total += this.comments.length;
                }
                if (this.likes) {
                    total += this.likes.length;
                }                    
                if (total > 0) {
                    emit(this.playerId, total);
                }
            }'
        )
        ->reduce(
            'function(key, values) {
                var total = 0;
                for (value in values) {
                    total += values[value];
                };
                return total;
            }'
        )->getQuery()->execute();

Как я могу оптимизировать этот запрос?Можете ли вы дать мне предложение для индексов?

1 Ответ

4 голосов
/ 15 марта 2012
->field('extra.targetPlayerId')->exists(FALSE)

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

из документов :

До версии 2.0, $ exist не может использовать индекс. Индексы по другим полям все еще используются. $ существует не очень эффективно даже с индексом , и особенно. с {$ Существует: истина}, поскольку он будет эффективно сканировать все проиндексированные значения.

Возможно, рассмотрите возможность добавления логического поля таким образом, чтобы вы могли проверять наличие истинного / ложного, а не существующего, и включить это поле в индекс.

Или даже переместить это конкретное условие в функцию карты:

function() {
    var total = 0;

    if (!this.extra || !this.extra.targetPlayerId) {
        return; //bail - count nothing
    }

    if (this.comments) {
        total += this.comments.length;
    }
    if (this.likes) {
        total += this.likes.length;
    }                    
    if (total > 0) {
        emit(this.playerId, total);
    }
}

Индексирование не является черно-белым ответом, например, если у вас много данных:

{
    time: 1,
    permission: 1,
    extra.hasTargetPlayer: 1
}

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

Кроме того, может быть более уместным просто изменить схему данных. Вы сохраняете результат этого запроса?

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

db.appstats.findOne({_id: "201152"})

где _id - год и номер недели. Если вы генерируете статистику по неделям, каждую неделю - вы можете выполнять тяжелый запрос по расписанию (cron), и поэтому на скорость запроса пользователей не влияет фактический расчет результатов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...