2012-03-15 63 views
1

該查詢在我的應用程序中花費了很多時間。數據庫包含約200萬條記錄。在Doctrine上優化MongoDB查詢

$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(); 

如何優化此查詢?你能給我提供索引建議嗎?

回答

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

那麼這可能是您查詢速度加快的最大障礙。

the docs

V2.0之前,$存在不能使用索引。其他字段的索引仍然使用。 $存在即使索引也不是非常有效,特別是,與{$ 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是一年weeknumber。如果您按星期,每週生成統計信息 - 您可以按計劃執行大量查詢(cron),因此用戶不會受到查詢速度以實際計算結果的影響。