我有一个mongodb distinct查询的习惯行为。目前,我正在使用2.6.10版本。 好吧,让我们创建一个简单的集合进行测试并解释。
from pymongo import MongoClient
import random
client = MongoClient('127.0.0.1', 27017)
client.DBTEST.random.remove({})
value = 0
BATCH_LEN = 16384
BATCH = []
for i in xrange(0, 500000):
BATCH.append({
"product": "value_uniq_1",
"number": value
})
if random.randint(0, 100) <= 1:
value = i
if len(BATCH) > BATCH_LEN:
client.DBTEST.random.insert(BATCH)
BATCH = []
client.DBTEST.random.insert(BATCH)
BATCH = []
好的,它会创建集合chich包含这样的文档
╔══════════════╦════════╗
║ product ║ number ║
╠══════════════╬════════╣
║ value_uniq_1 ║ 1 ║
║ value_uniq_1 ║ 1 ║
║ value_uniq_1 ║ 1 ║
║ value_uniq_1 ║ 56 ║
║ value_uniq_1 ║ 56 ║
║ value_uniq_1 ║ 56 ║
║ ... ║ ... ║
║ value_uniq_1 ║ 150054 ║
║ value_uniq_1 ║ 150054 ║
║ value_uniq_1 ║ 150054 ║
╚══════════════╩════════╝
现在,product
只有1个唯一值,但是,在不久的将来(1周),它会增加到近30个不同的字符串值,如下所示:
╔══════════════╦════════╗
║ product ║ number ║
╠══════════════╬════════╣
║ value_uniq_1 ║ 1 ║
║ value_uniq_1 ║ 1 ║
║ value_uniq_1 ║ 1 ║
║ value_uniq_1 ║ 56 ║
║ value_uniq_1 ║ 56 ║
║ value_uniq_1 ║ 56 ║
║ ... ║ ... ║
║ value_uniq_1 ║ 150054 ║
║ value_uniq_1 ║ 150054 ║
║ value_uniq_1 ║ 150054 ║
║ value_uniq_2 ║ 987 ║
║ value_uniq_2 ║ 987 ║
║ value_uniq_2 ║ 987 ║
╚══════════════╩════════╝
好的,我完成了我的数据结构,现在让我们看一下mongodb查询。
我的主要目标是为某些number
获取product
的所有唯一值。
我是这样做的:
db.random.distinct("number", {product: "value_uniq_1"})
好的,这对于调试来说并不是很冗长,我将在下一行中使用db.runCommand
。但是,现在,让我们避免使用查询来查看stats
部分的不同和外观:
db.runCommand({distinct: 'random', key:'number'})
"stats" : {
"n" : 500000,
"nscanned" : 500000,
"nscannedObjects" : 500000,
"timems" : 479,
"cursor" : "BasicCursor"
},
没关系,因为我们还没有创建索引,我们可以添加number
字段:
db.random.createIndex({number: 1})
重新运行上一个查询:
db.runCommand({distinct: 'random', key:'number'})
"stats" : {
"n" : 10005,
"nscanned" : 10005,
"nscannedObjects" : 0,
"timems" : 83,
"cursor" : "DistinctCursor"
},
很好,它使用索引,一切正常! 0 nscannedObjects !!!
好的,我们可以为distinct添加查询:
db.runCommand({distinct: 'random', key:'number', query: {product: "value_uniq_1"}})
"stats" : {
"n" : 500000,
"nscanned" : 500000,
"nscannedObjects" : 500000,
"timems" : 694,
"cursor" : "BasicCursor"
},
这不是我们所期望的(“nscannedObjects”:500000),但是,没有产品索引,让我们创建一个:
db.random.createIndex({product: 1, number: -1})
方向与任何组合没有区别 产品:1,数字-1或产品-1,数字1,OR产品:1,数字:1给出相同的行为。我检查了所有组合。
db.runCommand({distinct: 'random', key:'number', query: {product: "value_uniq_1"}})
"stats" : {
"n" : 500000,
"nscanned" : 500000,
"nscannedObjects" : 500000,
"timems" : 968,
"cursor" : "BtreeCursor product_1_number_-1"
},
WTF正在进行中? 为什么要使用索引扫描所有集合?目前,整个集合只包含一个产品价值,我无法猜测不同产品会有什么用。常见的不同查询为什么这么慢? 1秒它太慢了......
我不想为每个product
使用单独的集合,这是疯狂和低效的,因为我需要在所有产品之间进行共享查询。我的真实数据库每个产品包含超过500万个数字,此查询需要3秒多的时间。
答案 0 :(得分:1)
我正在使用3.0.2,看起来,它利用索引但仍然不知道为什么扫描所有记录, 我在我的mongodb中创建了相同的集合,并创建了索引。 查询“数字”字段的不同值表明它扫描了20K的记录(这是我插入的记录总数)
请参阅此图像,其中显示了计划摘要中的索引扫描。
https://www.dropbox.com/s/dh3tglyg4lsaqmm/distinct_explain_plan.png?dl=0
> db.random.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.random"
},
{
"v" : 1,
"key" : {
"product" : 1,
"number" : 1
},
"name" : "product_1_number_1",
"ns" : "test.random"
},
{
"v" : 1,
"key" : {
"number" : 1
},
"name" : "number_1",
"ns" : "test.random"
}
]