为什么 MongoDB 不使用索引交集?
Why MongoDB doesn't use Index Intersection?
我正在尝试重现索引交集指令的第一个示例 (http://docs.mongodb.org/manual/core/index-intersection/) 但面临一个问题:mongo 没有同时使用两个索引
我的步数:
- 下载mongo (3.0.3) 并安装
- 运行 mongod: mongod.exe --dbpath d:\data (文件夹为空)
- 运行 mongo: mongo.exe
添加索引:
db.orders.ensureIndex({ qty: 1 })
db.orders.ensureIndex({ item: 1 })
db.orders.getIndexes()
[{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.orders"
},
{
"v" : 1,
"key" : {
"qty" : 1
},
"name" : "qty_1",
"ns" : "test.orders"
},
{
"v" : 1,
"key" : {
"item" : 1
},
"name" : "item_1",
"ns" : "test.orders"
}]
检查查询说明:
db.orders.find( { item: "abc123", qty: { $gt: 15 } } ).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.orders",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"item" : {
"$eq" : "abc123"
}
},
{
"qty" : {
"$gt" : 15
}
}
]
},
"winningPlan" : {
"stage" : "KEEP_MUTATIONS",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"qty" : {
"$gt" : 15
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"item" : 1
},
"indexName" : "item_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"item" : [
"[\"abc123\", \"abc123\"]"
]
}
}
}
},
"rejectedPlans" : [
{
"stage" : "KEEP_MUTATIONS",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"item" : {
"$eq" : "abc123"
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"qty" : 1
},
"indexName" : "qty_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"qty" : [
"(15.0, 1.#INF]"
]
}
}
}
}
]
},
"serverInfo" : {
"host" : "localhost",
"port" : 27017,
"version" : "3.0.3",
"gitVersion" : "b40106b36eecd1b4407eb1ad1af6bc60593c6105"
},
"ok" : 1
}
如您所见,winningPlan 仅包含 item_1 索引。有包含 qty_1 索引的 rejectedPlans。但是没有包含索引交集的计划。
我知道 select 特定索引有很多条件。但就我而言 mongo 甚至没有计划!
有人能帮帮我吗?
SERVER-3071 JIRA issue 中有一些关于索引选择的详细信息,但我不能说是否所有内容都与 3.0 相关。不管怎样:
MongoDB 3.0.2 似乎 不考虑 range 查询的索引交互。但它将用于点间隔:
> db.orders.find( { item: {$eq : "abc123"}, qty: { $eq: 15 } } ).explain()
...
{
"stage" : "FETCH",
"inputStage" : {
"stage" : "KEEP_MUTATIONS",
"inputStage" : {
"stage" : "AND_SORTED",
"inputStages" : [
{
"stage" : "IXSCAN",
"keyPattern" : {
"qty" : 1
},
"indexName" : "qty_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"qty" : [
"[15.0, 15.0]"
]
}
},
{
"stage" : "IXSCAN",
"keyPattern" : {
"item" : 1
},
"indexName" : "item_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"item" : [
"[\"abc123\", \"abc123\"]"
]
}
}
]
}
我们正在托管一个多租户网站。所以有一个 mongo 集合包含所有客户的一些信息,例如
{customerId: 22, category: "category", region: "region", balance: 23434... }
在了解了Index Intersection之后,我们尝试创建多个单字段索引来支持不同查询条件的可变字段查询,比如
{ customerId: 22, category: "1" }
{ customerId: 22, region: "somewhere" }
{ customerId: 22, balance: {$gt:0} }
{ customerId: 22, region: {$in: ["R1", "R2"]},balance: {$gt:0} }
....
但从 "db.collection.explain" 中学习,结果并没有发生交集。
由于字段有限,我们最终找到了构建包含所有字段的复合索引的解决方案。
{customerId: 1, category: 1, region: 1, balance:1...}
然后发现下面所有查询都使用 "large" 复合索引,只要 "customerId" 在查询中。
{ customerId: 22, category: "1" }
{ customerId: 22, region: "somewhere" }
{ customerId: 22, balance: {$gt:0} }
{ customerId: 22, region: {$in: ["R1", "R2"]},balance: {$gt:0} }
....
我正在尝试重现索引交集指令的第一个示例 (http://docs.mongodb.org/manual/core/index-intersection/) 但面临一个问题:mongo 没有同时使用两个索引
我的步数:
- 下载mongo (3.0.3) 并安装
- 运行 mongod: mongod.exe --dbpath d:\data (文件夹为空)
- 运行 mongo: mongo.exe
添加索引:
db.orders.ensureIndex({ qty: 1 }) db.orders.ensureIndex({ item: 1 }) db.orders.getIndexes() [{ "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.orders" }, { "v" : 1, "key" : { "qty" : 1 }, "name" : "qty_1", "ns" : "test.orders" }, { "v" : 1, "key" : { "item" : 1 }, "name" : "item_1", "ns" : "test.orders" }]
检查查询说明:
db.orders.find( { item: "abc123", qty: { $gt: 15 } } ).explain() { "queryPlanner" : { "plannerVersion" : 1, "namespace" : "test.orders", "indexFilterSet" : false, "parsedQuery" : { "$and" : [ { "item" : { "$eq" : "abc123" } }, { "qty" : { "$gt" : 15 } } ] }, "winningPlan" : { "stage" : "KEEP_MUTATIONS", "inputStage" : { "stage" : "FETCH", "filter" : { "qty" : { "$gt" : 15 } }, "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "item" : 1 }, "indexName" : "item_1", "isMultiKey" : false, "direction" : "forward", "indexBounds" : { "item" : [ "[\"abc123\", \"abc123\"]" ] } } } }, "rejectedPlans" : [ { "stage" : "KEEP_MUTATIONS", "inputStage" : { "stage" : "FETCH", "filter" : { "item" : { "$eq" : "abc123" } }, "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "qty" : 1 }, "indexName" : "qty_1", "isMultiKey" : false, "direction" : "forward", "indexBounds" : { "qty" : [ "(15.0, 1.#INF]" ] } } } } ] }, "serverInfo" : { "host" : "localhost", "port" : 27017, "version" : "3.0.3", "gitVersion" : "b40106b36eecd1b4407eb1ad1af6bc60593c6105" }, "ok" : 1 }
如您所见,winningPlan 仅包含 item_1 索引。有包含 qty_1 索引的 rejectedPlans。但是没有包含索引交集的计划。 我知道 select 特定索引有很多条件。但就我而言 mongo 甚至没有计划!
有人能帮帮我吗?
SERVER-3071 JIRA issue 中有一些关于索引选择的详细信息,但我不能说是否所有内容都与 3.0 相关。不管怎样:
MongoDB 3.0.2 似乎 不考虑 range 查询的索引交互。但它将用于点间隔:
> db.orders.find( { item: {$eq : "abc123"}, qty: { $eq: 15 } } ).explain()
...
{
"stage" : "FETCH",
"inputStage" : {
"stage" : "KEEP_MUTATIONS",
"inputStage" : {
"stage" : "AND_SORTED",
"inputStages" : [
{
"stage" : "IXSCAN",
"keyPattern" : {
"qty" : 1
},
"indexName" : "qty_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"qty" : [
"[15.0, 15.0]"
]
}
},
{
"stage" : "IXSCAN",
"keyPattern" : {
"item" : 1
},
"indexName" : "item_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"item" : [
"[\"abc123\", \"abc123\"]"
]
}
}
]
}
我们正在托管一个多租户网站。所以有一个 mongo 集合包含所有客户的一些信息,例如
{customerId: 22, category: "category", region: "region", balance: 23434... }
在了解了Index Intersection之后,我们尝试创建多个单字段索引来支持不同查询条件的可变字段查询,比如
{ customerId: 22, category: "1" }
{ customerId: 22, region: "somewhere" }
{ customerId: 22, balance: {$gt:0} }
{ customerId: 22, region: {$in: ["R1", "R2"]},balance: {$gt:0} }
....
但从 "db.collection.explain" 中学习,结果并没有发生交集。 由于字段有限,我们最终找到了构建包含所有字段的复合索引的解决方案。
{customerId: 1, category: 1, region: 1, balance:1...}
然后发现下面所有查询都使用 "large" 复合索引,只要 "customerId" 在查询中。
{ customerId: 22, category: "1" }
{ customerId: 22, region: "somewhere" }
{ customerId: 22, balance: {$gt:0} }
{ customerId: 22, region: {$in: ["R1", "R2"]},balance: {$gt:0} }
....