2012-03-15 12 views
1

이 쿼리는 응용 프로그램에 많은 시간이 걸립니다. 데이터베이스에는 약 2 백만 개의 레코드가 들어 있습니다.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에서

:

2.0 전에 $가 존재하는 인덱스를 사용 할 수 없습니다. 다른 필드의 색인은 계속 사용됩니다. $ exists는 색인 및 esp를 사용해도 매우 효율적이지 않습니다. {$ exists : true}는 모든 인덱싱 된 값을 효과적으로 검색해야하기 때문에 사실입니다.

아마도 존재 대신 true/false를 테스트 할 수있는 부울 필드를 추가하고 해당 필드를 인덱스에 포함시키는 것이 좋습니다.

심지어지도 기능으로 특정 조건을 이동 :

{ 
    time: 1, 
    permission: 1, 
    extra.hasTargetPlayer: 1 
} 
: 당신은 많은 양의 데이터가있는 경우

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); 
    } 
} 

인덱싱, 예를 들어,하지 흑백 답변입니다

은 아마도 아주 잘 작동 할 것입니다. mongo가 첫 번째 기준으로 올바른 날짜 범위에 집중할 수있게 해주기 때문입니다.

단순히 데이터 스키마를 변경하는 것이 더 적절할 수 있습니다. 그 쿼리의 결과를 저장하고 있습니까?

즉 쿼리는 한 번하고 결과를 저장하므로 후속 요청에 대해 당신이 단지 수 :

_id는 년 weeknumber입니다
db.appstats.findOne({_id: "201152"}) 

. 매주 통계를 생성하는 경우 매주 - 일정에 따라 무거운 쿼리를 수행 할 수 있으므로 (cron) 쿼리 속도에 영향을받지 않으므로 결과를 실제로 계산할 수 있습니다.