0

以下は私の mongodb 3.0 クエリです。実行に長い時間 (4 秒以上) かかります。データセットはわずか 430 万のドキュメントです。

db.getCollection('TestingCollection').aggregate([ 
    { $match: { 
        myDate: { $gte: new Date(949384052490) }, 
        $and: [ 
            { 
                myDate: { $lte: new Date(1448257684431) }, 
                $and: [ { myId: 10 } ] 
            }
        ], 
        type: { $ne: "Contractor" } 
    }}, 
    { $project: { 
        retailerName: 1,
        unitSold: 1, 
        year: { $year: [ "$myDate" ] },
        currency: 1, 
        totalSales: { $multiply: [ "$unitSold", "$itemPrice" ] } 
    }}, 
    { $group: { 
        _id: { 
            retailerName: "$retailerName", 
            year: "$year",      
            currency: "$currency" 
        }, 
        netSales: { $sum: "$revenue" }, 
        netUnitSold: { $sum: "$unitSold" }, 
        totalSales: { $sum:"$totalSales" } 
    }}
] )

複合インデックス付きフィールド:

(myDate : 1, retailerName:1, type:1, myId:1).

と同じクエリ

type: { $eq: "Contractor" }

実行には数ミリ秒かかります。

私が間違っているところを教えてください。

4

1 に答える 1

2

「範囲選択」が正しく指定されておらず、 の使用法が$and正しくありません。実際には、「最後の」引数のみが考慮されているため、 「等しい日付よりも大きい」myId10すべてを探しているだけですが、これはもちろん正しくありません。

の正しいクエリ構文は次のとおりです$match

{ "$match": { 
    "myDate": { 
        "$gte": new Date(949384052490),
        "$lte": new Date(1448257684431)
    },
    "myId": 10,
    "type": { "$ne": "Contractor" }
}}

$andとにかく、すべての MongoDB クエリ引数は既にAND条件であるため、必要はありません。

$projectまた、との段階を組み合わせることも検討する必要があります。$groupこれは通常、これらが次々に発生したときに組み合わせることができることを意味します。少なくともその方が効率的です。

しかしもちろん、初期段階で多くの時間が浪費され$matchており、とにかく誤った結果を選択していたはずです。


$groupおよび no の最適なパイプライン$project:

{ "$group": { 
    "_id": { 
        "retailerName": "$retailerName", 
        "year": { "$year": "$myDate" },      
        "currency": "$currency"
    }, 
    "netSales": { "$sum": "$revenue" }, 
    "netUnitSold": { "$sum": "$unitSold" }, 
    "totalSales": { "$sum": 
        { "$multiply": [ "$unitSold", "$itemPrice" ] }
    }
}}

したがって、パイプライン全体はちょうど$matchthen$groupです。


春のmongoでの作業

spring-mongo を使用している場合、複合キーとアキュムレータの計算値を使用した、サポートされている演算子による結合には現在の制限があり$groupますが、これらを回避できます。ステートメントに関して$andは、それは実際には構文の問題であり、Spring mongo のせいではありません。

まず、集計パイプラインで「グループ」のカスタム クラスを設定します。

public class CustomGroupOperation implements AggregationOperation {
    private DBObject operation;

    public CustomGroupOperation (DBObject operation) {
        this.operation = operation;
    }

    @Override
    public DBObject toDBObject(AggregationOperationContext context) {
        return context.getMappedObject(operation);
    }
}

次に、そのクラスを使用してパイプラインを構築します。

    Aggregation aggregation = newAggregation(
        match(
                Criteria.where("myDate")
                        .gte(new Date(new Long("949384052490")))
                        .lte(new Date(new Long("1448257684431")))
                        .and("myId").is(10)
                        .and("type").ne("Contractor")
        ),
        new CustomGroupOperation(
            new BasicDBObject(
                "$group", new BasicDBObject(
                    "_id", new BasicDBObject(
                        "retailerName", "$retailerName"
                    ).append(
                        "year", new BasicDBObject("$year", "$myDate")
                    ).append(
                        "currency", "$currency"
                    )
                ).append(
                    "netSales", new BasicDBObject("$sum","$revenue")
                ).append(
                    "netUnitSold", new BasicDBObject("$sum","$unitSold")
                ).append(
                    "totalSales", new BasicDBObject(
                        "$multiply", Arrays.asList("$unitSold", "$itemPrice")
                    )
                )
            )
        )
    );

これにより、次のようなシリアル化されたパイプラインが生成されます。

[ 
    { "$match" : { 
        "myDate" : { 
            "$gte" : { "$date" : "2000-02-01T05:47:32.490Z"}, 
            "$lte" : { "$date" : "2015-11-23T05:48:04.431Z"}
        }, 
        "myId" : 10, 
        "type" : { "$ne" : "Contractor"}
    }}, 
    { "$group": { 
        "_id" : { 
            "retailerName" : "$retailerName", 
            "year" : { "$year" : "$myDate"}, 
            "currency" : "$currency"
        }, 
        "netSales" : { "$sum" : "$revenue"}, 
        "netUnitSold" : { "$sum" : "$unitSold"}, 
        "totalSales" : { "$multiply" : [ "$unitSold" , "$itemPrice"]}
    }}
]

これは、上記の例とまったく同じです

于 2015-11-23T06:30:26.127 に答える