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不正确。实际上,只考虑了“最后一个”参数,因此它只是在寻找“大于myId等于10的日期的所有内容,这当然是不正确的。

这是您的正确查询语法$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" ] }
    }
}}

所以整个管道现在就在$match那时$group


使用 spring 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 回答