2017-03-21 46 views
1

私は私がする必要があるいくつかのユースケースでMongodb.aggregateは()インデックス

jobId: 1 
result.status: 1 
jobId: 1, result.status: 1 

によってインデックスを有するおおよその構造その上で

{ 
    "_id" : "job-id_00000001_2017-03-17T21:30:38.510Z", 
    "jobId" : "job-id", 
    "result" : { 
     "status" : "ok" 
    }, 
    "..." : "..." 
} 

次でアーカイブされたタスクのコレクションを持っているが無視されます統計を頻繁に更新する(map:job-id - > status - > count)と、この集約関数を実行すると...

db.getCollection('jobs_archive').aggregate([ 
      {$group: { 
       _id: {jobId: "$jobId", status: "$result.status"}, 
       count: { $sum: 1 } 
      }} 
     ], {explain: true}) 

... 1.2ミリの行で〜4秒実行され、これは許容できないほど長いです。 explain: trueですべてのフィールドを私は...

"queryPlanner" : { 
    "plannerVersion" : 1, 
    "namespace" : "db.jobs_archive", 
    "indexFilterSet" : false, 
    "parsedQuery" : {}, 
    "winningPlan" : { 
     "stage" : "COLLSCAN", 
     "direction" : "forward" 
    }, 
    "rejectedPlans" : [] 
}  

を取得...とCOLLSCANはモンゴはそれにもかかわらず、インデックスからのデータを使用していないことを意味し、複合インデックスjobId: 1, result.status: 1でご利用いただけます。

aggregateクエリのパフォーマンスを最適化する方法はありますか?私は何か間違っているのですか?


(オリダルからの回答によってトリガ補遺)のドキュメントに多くの掘り後、私は「カバードクエリー」、私はそのような場合に使用されなければならないはずのような機能が気づきました。それはそうではないようです。 Aがクエリをカバーし https://docs.mongodb.com/manual/core/query-optimization/#covered-query

対象クエリは インデックスを使用して、完全に満足することができ、任意の書類を調査する必要はありませんクエリです。次の両方が適用されたときにインデックスが クエリをカバー:

  • クエリ内のすべてのフィールドは結果で返されるすべてのフィールドが同じインデックスにあるインデックスの一部であり、

...

インデックスがクエリで必要なすべてのフィールドが含まれているため、MongoDBの は、クエリ条件に一致するだけ インデックスを使用して結果を返すことができます両方。

インデックスのみのクエリは、インデックス外のドキュメント のクエリよりもはるかに高速です。インデックスキーは通常カタログ化されている のドキュメントよりも小さく、索引は通常ディスクに順次配置されたRAMまたは で利用できます。IXSCAN/"INDEXNAME": "jobId_1_result.status_1"

  • winningPlan:IXSCAN /「INDEXNAMEモンゴ

    (1) db.getCollection('jobs_archive').find({"jobId" : "job-id"}).count() 
    --> 0.375sec, count = 430000 
    
    (2) db.getCollection('archive').find({"jobId" : "job-id", "result.status": "ok"}).count() 
    --> 1.400sec, count = 430000 
    

    explain()から


  • よりすごみは

    1. winningPlanを語ります":" jobId_1 "

    Mongoがインデックスを正しく使用する場合は、 'job-id + status'(6 * 5)の組み合わせごとに 'query()。count()'を使用しますが、この場合も。

    RRRR ...私は両方のキー「JOBID + result.status」複合インデックスがcount()のために使用されていない指定...と私は複合インデックスが使用され、クエリで一つだけjobIdを指定するとき注:Mongoの「バージョン」 : "3.4.2"、Ubuntuの16

    答えて

    1

    Pipeline Operators and Indexes

    パイプライン演算子とIndexes¶での利点を取ることができ

    $マッチと$並べ替えパイプライン事業者から彼らがパイプラインの始めに発生したときに、

    MongoDBの$group

    ため使用インデックスあなたはすべての文書が処理されるという意味で、フルスキャンを行っていません。したがって、インデックスを使用すると、ドキュメントごとに重複した参照が発生します。つまり、インデックス用に1回、ドキュメント用に1回、ということです。

    したがって、索引は、最初に$matchフィルタを使用して結果を絞り込んだ場合にのみ使用できます。

    補足として、{jobId: 1}のインデックスは冗長です。 *「MongoDBは$グループのインデックスを使用しません」Prefixes

    +0

    は、なぜあなたは*思います参照してくださいdb.jobs_archive.find({jobId: n})

    クエリオプティマイザは、次のパターンを使用してクエリの{jobId: 1, result.status: 1}インデックスを使用することができますか?私は彼らの文書を見て、そのような声明を見つけませんでした。代わりに、私は 'Covered Query'(私の質問の補遺参照)に関する注釈を見つけました。これはまさに私のケースですが、何らかの理由でうまくいかないようです。 –

    +0

    リファレンスドキュメントから引用した文章では正確に述べているためです。また、カバーされたクエリを使用していません。カバードクエリを使用するには、正確なインデックスフィールドに '$ match 'する必要があります。また、_idフィールドも除外してください。 –

    +0

    ' db.jobs_archive.explain()。aggregate({$ match:{jobId:1}}、 $ group:{idid:{jobId: "$ jobId"、ステータス: "$ result.status"}、件数:{$ sum:1}}}) 'と表示されます。 –

    関連する問題