2015-06-29 1 views
4

У меня было поведение в поведении с помощью отдельного запроса mongodb. В настоящее время я использую версию 2.6.10. Хорошо, давайте создадим простую коллекцию для теста с объяснениями.MongoDB не использует индексы для отдельных с простым запросом

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 = [] 

Ok, это создаст коллекцию Чич содержит документы, как этот

╔══════════════╦════════╗ 
║ 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 ║ 
╚══════════════╩════════╝ 

Теперь у меня есть только 1 уникальное значение для product, но в ближайшем будущем (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 ║ 
╚══════════════╩════════╝ 

Ok, я закончил с моей структуры данных, теперь давайте посмотрим немного 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}) 

ReRun предыдущего запрос:

db.runCommand({distinct: 'random', key:'number'}) 

"stats" : { 
    "n" : 10005, 
    "nscanned" : 10005, 
    "nscannedObjects" : 0, 
    "timems" : 83, 
    "cursor" : "DistinctCursor" 
}, 

Отлично, он использует индексы, и все работает нормально! nscannedObjects !!!

Хорошо, давайте добавим запрос для отчетливый:

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, ИЛИ продукт: 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, она сумасшедшая и неэффективная, потому что мне нужны общие запросы между всеми продуктами. Моя реальная БД содержит более 5 миллионов номеров на один продукт, и для этого запроса требуется больше 3 секунд.

+0

Возможный дубликат [MongoDB - отчетливый с запросом не использует индексы] (http://stackoverflow.com/questions/36006208/mongodb-distinct-with-query-doesnt-use -Indexes) – Robert

ответ

1

Я использую 3.0.2, Looks, используя индекс, но до сих пор не знаю, почему его сканирование всех записей, Я создал ту же коллекцию в моем mongodb и создал индексы. , запрашивающий отдельные значения поля «число», показывает, что он сканировал 20 тыс. Повторений (которые представляют собой общее количество записей, которые я вставил)

Пожалуйста, обратитесь к этому изображению, где оно отображает сканирование индекса в сводке плана.

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" 
    } 
] 
+0

То текстовое представление вашего изображения: "Статистика": { "п": 20000, "nscanned": 20000, "nscannedObjects": 20000, "timems": 24, "planSummary" : «IXSCAN {продукт: 1.0, номер: 1.0}» } – libbkmz

+0

Какой размер коллекции? – libbkmz

+0

Как упоминалось 20K –

Смежные вопросы