在Doctrine上优化MongoDB查询

时间:2012-03-15 16:10:42

标签: php mongodb doctrine database nosql

此查询在我的应用程序中花费了很多时间。数据库包含大约200万条记录。

    $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 个答案:

答案 0 :(得分:4)

->field('extra.targetPlayerId')->exists(FALSE)

这可能是你加快查询速度的最大障碍。

来自the docs

  

在v2.0之前,$ exists无法使用索引。仍然使用其他字段的索引。    $存在即使使用索引也不是很有效,尤其是使用{$ exists:true},因为它实际上必须扫描所有索引值。

也许考虑添加一个布尔字段,以便您可以测试true / false而不是exists - 并在索引中包含该字段。

甚至可以将特定条件移动到地图功能中:

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
}

可能会运作得很好 - 因为它可以让mongo专注于正确的日期范围作为第一个标准。

除此之外,简单地更改数据模式可能更合适。您是否存储该查询的结果?

即。查询一次并存储结果,以便您可以执行任何后续请求:

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

其中_id是年份和周数。如果您按周,每周生成统计数据 - 您可以按计划(cron)执行繁重的查询,因此用户不会受查询速度的影响,无法实际计算结果。