2016-04-20 86 views
0

我想了解索引如何应用到这个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] 
    } 
} 

我明白,这可能是一个缓慢的查询,但我想看看别人会攻击创建索引。这可能是重新组织查询的问题吗?

回答

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" : "blahblah", "$options" : "i"} 

如果不区分大小写可以不完成,我们可以假定的任期可以永远是一个“打头......”值,再下面是非常快:

{"$regex" : "^blahblah"} 

请注意,最后没有“*”,因为它是隐含的。见https://docs.mongodb.org/v3.0/reference/operator/query/regex/

0

我将与您的查询的三个主要领域是创建一个复合索引开始,因为它是一个低挂水果的方式:

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

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

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

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