2014-09-26 2 views
2

У меня действительно простой запрос манго, который должен использовать индекс _id. Explain, план выглядит хорошо:MongoDB медленные запросы

> db.items.find({ deleted_at: null, _id: ObjectId('541fd8016d792e0804820100') }).sort({ positions: 1 }).explain() 
{ 
    "cursor" : "BtreeCursor _id_", 
    "isMultiKey" : false, 
    "n" : 1, 
    "nscannedObjects" : 1, 
    "nscanned" : 1, 
    "nscannedObjectsAllPlans" : 6, 
    "nscannedAllPlans" : 7, 
    "scanAndOrder" : true, 
    "indexOnly" : false, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "millis" : 0, 
    "indexBounds" : { 
     "_id" : [ 
      [ 
       ObjectId("541fd8016d792e0804820100"), 
       ObjectId("541fd8016d792e0804820100") 
      ] 
     ] 
    }, 
    "server" : "mydbserver:27017", 
    "filterSet" : false 
} 

Но когда я выполнить запрос он выполняет в 100-800ms:

> db.items.find({ deleted_at: null, _id: ObjectId('541fd8016d792e0804820100') }).sort({ positions: 1 }) 
2014-09-26T12:34:00.279+0300 [conn38926] query mydb.items query: { query: { deleted_at: null, _id: ObjectId('541fd8016d792e0804820100') }, orderby: { positions: 1.0 } } planSummary: IXSCAN { positions: 1 } ntoreturn:0 ntoskip:0 nscanned:70043 nscannedObjects:70043 keyUpdates:0 numYields:1 locks(micros) r:1391012 nreturned:1 reslen:814 761ms 

Почему отчетность nscanned:70043 nscannedObjects:70043 и почему это так медленно?

Я использую MongoDB 2.6.4 на CentOS 6.

Я пытался ремонт MongoDB, полный дамп/импорт, не помогает.

Update 1

> db.items.find({deleted_at:null}).count() 
67327 
> db.items.find().count() 
70043 

не имеют индекс на deleted_at, но у меня есть индекс по _id.

Update 2 (2014-09-26 14:57 EET)

Добавление индекса на _id, deleted_at не помогает, даже explain не использует индекс :(

> db.items.ensureIndex({ _id: 1, deleted_at: 1 }, { unique: true }) 
> db.items.getIndexes() 
[ 
    { 
     "v" : 1, 
     "key" : { 
      "_id" : 1 
     }, 
     "name" : "_id_", 
     "ns" : "mydb.items" 
    }, 
    { 
     "v" : 1, 
     "unique" : true, 
     "key" : { 
      "_id" : 1, 
      "deleted_at" : 1 
     }, 
     "name" : "_id_1_deleted_at_1", 
     "ns" : "mydb.items" 
    } 
] 
> db.items.find({ deleted_at: null, _id: ObjectId('541fd8016d792e0804820100') }).sort({ positions: 1 }).explain() 
{ 
    "cursor" : "BtreeCursor _id_", 
    "isMultiKey" : false, 
    "n" : 1, 
    "nscannedObjects" : 1, 
    "nscanned" : 1, 
    "nscannedObjectsAllPlans" : 7, 
    "nscannedAllPlans" : 8, 
    "scanAndOrder" : true, 
    "indexOnly" : false, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "millis" : 0, 
    "indexBounds" : { 
     "_id" : [ 
      [ 
       ObjectId("541fd8016d792e0804820100"), 
       ObjectId("541fd8016d792e0804820100") 
      ] 
     ] 
    }, 
    "server" : "myserver:27017", 
    "filterSet" : false 
} 

Обновление 3 (2014-09-26 15:03:32 EET)

Добавлен индекс на _id, deleted_at, positions. Но все же кажется странным, что предыдущие дела заставляют l просмотр коллекции.

> db.items.ensureIndex({ _id: 1, deleted_at: 1, positions: 1 }) 
> db.items.find({ deleted_at: null, _id: ObjectId('541fd8016d792e0804820100') }).sort({ positions: 1 }).explain() 
{ 
    "cursor" : "BtreeCursor _id_1_deleted_at_1_positions_1", 
    "isMultiKey" : false, 
    "n" : 1, 
    "nscannedObjects" : 1, 
    "nscanned" : 1, 
    "nscannedObjectsAllPlans" : 3, 
    "nscannedAllPlans" : 3, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "millis" : 0, 
    "indexBounds" : { 
     "_id" : [ 
      [ 
       ObjectId("541fd8016d792e0804820100"), 
       ObjectId("541fd8016d792e0804820100") 
      ] 
     ], 
     "deleted_at" : [ 
      [ 
       null, 
       null 
      ] 
     ], 
     "positions" : [ 
      [ 
       { 
        "$minElement" : 1 
       }, 
       { 
        "$maxElement" : 1 
       } 
      ] 
     ] 
    }, 
    "server" : "myserver:27017", 
    "filterSet" : false 
} 
+0

Вы сделали индекс в поле 'deleted_at'? Вы можете выполнить тест на 'db.item.find ({deleted_at: null}). Count()' для сравнения с '70043'. – Wizard

+0

Я обновил свой вопрос с помощью подсчетов – na43251

+0

Почему вы используете сортировку, когда количество отсканированных записей должно быть не более 1, поскольку вы фильтруете на основе уникального идентификатора? –

ответ

1

Это похоже на ошибку. Планировщик запросов должен выбрать индекс _id, а индекс _id должен быть всем необходимым, так как он должен немедленно уменьшить набор результатов до одного документа. Сорт должен быть неактуальным, поскольку он заказывает один документ. Это странный случай, потому что вы явно запрашиваете один документ с совпадением _id, а затем сортируете его. Вы должны быть в состоянии обойти мангоид и бросить сортировку в качестве обходного пути.

.explain() не игнорирует сортировку. Вы можете проверить, что просто так:

> for (var i = 0; i < 100; i++) { db.sort_test.insert({ "i" : i }) } 
> db.sort_test.ensureIndex({ "i" : 1 }) 
> db.sort_test.find().sort({ "i" : 1 }).explain() 

Если MongoDB не может использовать индекс для сортировки, он сортирует в памяти. Поле scanAndOrder в описании объясняет, может ли MongoDB не использовать индекс для сортировки результатов запроса (т. Е. scanAndOrder : false означает, что MongoDB может использовать индекс для сортировки результатов запроса).

Не могли бы вы предоставить отчет об ошибке в MongoDB SERVER project? Возможно, инженеры скажут, что он работает так, как было разработано, но поведение выглядит неправильным для меня, и в пакете 2.6.4 уже есть пара запросов. Возможно, я пропустил это, если это было сказано ранее, но влияет ли присутствие/отсутствие deleted_at : null на проблему?

Кроме того, если вы разместите билет, разместите ссылку на него в своем вопросе или в качестве комментария к этому ответу, чтобы другим было легко следовать. Благодаря!

+0

По интуиции '.explain()' должен включать '.sort()'. Но на самом деле руководство просто утверждает, что оно делает суждение. В противном случае, я не думаю, что приведенный выше пример может доказать '.explain()', по-видимому, включать '.sort()'. Моей причиной является то, что в результате был предоставлен вопросник, поскольку количество документов после индексного запроса - только одно, поэтому операция 'sort' не нужна. 'ScanAndOrder' должен быть' false', но это 'true'. Зачем? Я думаю, '.explain()' просто делает суждение независимо от конечного результата запроса. – Wizard

-2

Я предполагаю, что у вас есть 70043 объектов с идентификатором «541fd8016d792e0804820100». Можете ли вы просто найти на этом id и count() их? Индекс не означает «уникальный» индекс - если у вас есть индекс «bucket» с определенным значением, после достижения ведра он теперь выполняет сканирование в ведре, чтобы посмотреть на каждое значение «deleted_at», чтобы увидеть, ноль'. Чтобы обойти это, используйте составной индекс (id, deleted_at).

+0

_id в mongodb - специальный уникальный индекс, аналогичный первичному ключу в реляционных базах данных. Не может быть указателя «ведро». Infact, насколько я знаю, в mongodb есть только составные или сеновальные индексы, без ведер. –

+0

У меня есть 1 документ с идентификатором 541fd8016d792e0804820100 – na43251

+0

@ na43251. Не могли бы вы сделать тест на 'db.items.find ({deleted_at: null, _id: ObjectId ('541fd8016d792e0804820100')}). Hint ({_ id: 1}). sort ({position: 1}) 'перед созданием этого составного индекса, который вы сделали? Если вы все еще просматриваете столько документов, я думаю, что это ошибка! – Wizard

-1

UPDATE:исправил мой ответ, который предложил использовать (_id, deleted_at) соединение index.Also в комментариях, больше ясности относительно того, как объяснить() может не отражать планировщик запросов в некоторых случаях.

Что мы ожидаем, так это то, что find() будет фильтровать результаты, а затем sort() будет применяться к фильтруемому набору. Однако, согласно документу this, планировщик запросов будет не использовать индекс на _id, а также индекс (если есть) на postion для этого запроса. Теперь, если у вас есть составной индекс на (_id, position), он должен иметь возможность использовать этот индекс для обработки запроса.

Суть в том, что если у вас есть указатель, то ваш запрос может быть уверен в том, что ваш индекс используется планировщиком запросов. В вашем случае запрос определенно не покрывается, как указано в indexOnly : false в плане объяснения.

Если это по дизайну, оно деиствительно контр-интуитивно и как wdberkely suggested, вы должны подать отчет об ошибке, чтобы сообщество получило более подробное объяснение этого своеобразного поведения.

+0

Я попробовал добавить индекс id, deleted_at', не помогает, см. ** Обновление 2 ** – na43251

+0

Действительно ли нужно сканировать полную коллекцию, а не набор результатов, который был отфильтрован с помощью 'find'? С предыдущими версиями mongodb у меня не было этой проблемы. – na43251

+1

О вашем заявлении 'Он игнорирует sort() part' во время'.explain() ', вы могли бы поделиться некоторыми официальными или твердыми доказательствами об этом? Благодарю. – Wizard

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