Mongo索引帮助$或查询

时间:2016-04-20 18:48:16

标签: mongodb indexing

我试图了解如何将索引应用于此MongoDB查询:

{
    "account_id" : 1234,
    "supplier_id" : {
        "$gt" : 0
    },
    "$or" : [
        {
            "po_number" : {
                "$regex" : "blahblah",
                "$options" : "i"
            }
        },
        {
            "shipping.first_name" : {
                "$regex" : "blahblah",
                "$options" : "i"
            }
        },
        {
            "shipping.last_name" : {
                "$regex" : "blahblah",
                "$options" : "i"
            }
        },
        {
            "shipping.company" : {
                "$regex" : "blahblah",
                "$options" : "i"
            }
        },
        {
            "consumer_order_number" : "blahblah"
        },
        {
            "invoices.invoice_number" : "blahblah"
        },
        {
            "shipments.tracking_number" : "blahblah"
        }
    ],
    "test_flag" : {
        "$in" : [0,null]
    }
}

我知道这可能是一个缓慢的查询,但我想看看其他人如何攻击为它创建索引。可能是重新组织查询的问题吗?

2 个答案:

答案 0 :(得分:0)

我开始的方式是在查询的主要三个字段上创建一个复合索引,因为它是一个悬而未决的结果:

db.yourcollection.createIndex({account_id: 1, test_flag: 1, supplier_id: 1})

1表示按增加键顺序创建的范围索引。特别是,它支持supplier_id上的$ gt查询。

订单可以使用,特别是最后两个,但是account_id可能应该保持优先:您的查询对它有高度选择性,因此最好有一个索引将相同的account_id保持在一起。

然后将在内存中执行$或部分查询,如果以上三个字段是选择性的,那么这应该足够好。

答案 1 :(得分:0)

因此,在经过一系列测试之后,事实证明需要重写查询以允许它充分利用多个索引。重写版本是:

{
"$or" : [
    {
        "po_number" : {"$regex" : "blahblah", "$options" : "i"}
        "account_id" : 1234,
        "supplier_id" : {"$gt" : 0},
        "test_flag" : {"$in" : [0,null]}
    },
    {
        "shipping.first_name" : {"$regex" : "blahblah", "$options" : "i"}
        "account_id" : 1234,
        "supplier_id" : {"$gt" : 0},
        "test_flag" : {"$in" : [0,null]}
    },
    {
        "shipping.last_name" : {"$regex" : "blahblah", "$options" : "i"}
        "account_id" : 1234,
        "supplier_id" : {"$gt" : 0},
        "test_flag" : {"$in" : [0,null]}
    },
    {
        "shipping.company" : {"$regex" : "blahblah", "$options" : "i"}
        "account_id" : 1234,
        "supplier_id" : {"$gt" : 0},
        "test_flag" : {"$in" : [0,null]}
    },
    {
        "consumer_order_number" : "blahblah"
        "account_id" : 1234,
        "supplier_id" : {"$gt" : 0},
        "test_flag" : {"$in" : [0,null]}
    },
    {
        "invoices.invoice_number" : "blahblah"
        "account_id" : 1234,
        "supplier_id" : {"$gt" : 0},
        "test_flag" : {"$in" : [0,null]}
    },
    {
        "shipments.tracking_number" : "blahblah"
        "account_id" : 1234,
        "supplier_id" : {"$gt" : 0},
        "test_flag" : {"$in" : [0,null]}
    }
],

}

请注意唯一的顶级元素是" $或"。如果有任何其他顶级元素,则只能使用单个索引。我创建了以下索引最终使用的索引:

db.Order.ensureIndex({po_number: 1, account_id: -1, supplier_id: -1});
db.Order.ensureIndex({"shipping.first_name": 1, account_id: -1, supplier_id: -1});
db.Order.ensureIndex({"shipping.last_name": 1, account_id: -1, supplier_id: -1});
db.Order.ensureIndex({"shipping.company": 1, account_id: -1, supplier_id: -1});
db.Order.ensureIndex({consumer_order_number: 1, account_id: -1, supplier_id: -1});
db.Order.ensureIndex({"invoices.invoice_number": 1, account_id: -1, supplier_id: -1});
db.Order.ensureIndex({"shipments.tracking_number": 1, account_id: -1, supplier_id: -1});

作为旁注,我还通过更改$ regex条目找到了很多速度。

由于不区分大小写,此版本最慢,并且允许在字符串的中间找到该术语。

{"$regex" : "blahblah", "$options" : "i"}

如果不能不区分大小写,我们可以假设该术语始终是"以...开始..."价值,那么以下是非常快的:

{"$regex" : "^blahblah"}

请注意,没有" *"最后,因为它暗示。请参阅https://docs.mongodb.org/v3.0/reference/operator/query/regex/