2013-05-12 2 views
3

Моя структура документа выглядит следующим образом

{ 
    "_id" : "311acd33a0ae8dcc3101246f90af9dc5", 
    "created_datetime" : ISODate("2013-04-05T10:35:31.143Z"), 
    "installs" : [ 
     { 
      "status" : 1, 
      "app" : "xyz", 
      "reg_id" : "AVJyaIFI2Q8v93YmOHI5kEOVoCLbd4CAUyVK9zLrC1QCiBcl_bw89i5PvhEuTKmxtb4x130vjMyo78zPI7cedErcRv_Jjn0BN3Wq40hhg", 
      "last_action_datetime" : ISODate("2013-04-05T10:35:31.143Z"), 
      "version" : "2" 
     }, 
     { 
      "status" : 1, 
      "app" : "abc",             
      "reg_id" : "AVJyaIFI2Q8v93YmOHI5kEOVoCLbd4CAUyVK9zLrC1QCiBcl_bw89i5PvhEuTKmxtb4x130vjMyo78zPI7cedErcRv_Jjn0BN3Wq40hhg", 
      "last_action_datetime" : ISODate("2013-04-05T10:35:31.143Z"), 
      "version" : "5" 
     }, 
     { 
      "status" : 1, 
      "app" : "pqr",             
      "last_action_datetime" : ISODate("2013-04-06T10:35:31.143Z"), 
      "version" : "1" 
     }, 
    ], 
    "last_update" : ISODate("2013-04-12T06:26:46.333Z"), 
    "num_updates" : 9, 
    ..... 
} 

и у меня есть составной индекс на 'install.reg_id' и 'installs.status' и один индекс 'installs.status'

Теперь я хочу найти все документы, где, по меньшей мере, на элемент installs содержит reg_id, а также его status равен 1. Таким образом, я запрос

db.users.find({'installs': {'$elemMatch': {'reg_id': {'$exists': true}, 'status': 1}}}).explain() 

я получить

{ 
     "cursor" : "BtreeCursor installs.status_1", 
     "isMultiKey" : true, 
     "n" : 1447034, 
     "nscannedObjects" : 1720864, 
     "nscanned" : 1720864, 
     "nscannedObjectsAllPlans" : 1720864, 
     "nscannedAllPlans" : 1720864, 
     "scanAndOrder" : false, 
     "indexOnly" : false, 
     "nYields" : 13072, 
     "nChunkSkips" : 0, 
     "millis" : 11063, 
     "indexBounds" : { 
       "installs.status" : [ 
         [ 
           1, 
           1 
         ] 
       ] 
     }, 
     "server" : "####:27017" 
} 

Так вот составной индекс должен был использоваться, но не используется. Я думал, что $elemMatch является виновником, так что я сделал этот запрос,

db.users.find({'installs.reg_id': {'$exists': true}}).explain() 

и я получаю

{ 
     "cursor" : "BasicCursor", 
     "isMultiKey" : false, 
     "n" : 2947446, 
     "nscannedObjects" : 3184871, 
     "nscanned" : 3184871, 
     "nscannedObjectsAllPlans" : 3184871, 
     "nscannedAllPlans" : 3184871, 
     "scanAndOrder" : false, 
     "indexOnly" : false, 
     "nYields" : 23865, 
     "nChunkSkips" : 0, 
     "millis" : 16172, 
     "indexBounds" : { 

     }, 
     "server" : "####:27017" 
} 

Это показывает, что запрос не использует какие-либо индексов.

Подумайте, что здесь не так?

Обновления: Добавление подсказки делает использование запроса индексы

db.users.find({'installs': {'$elemMatch': {'reg_id': {'$exists': true}, 'status': 1}}}).hint({"installs.reg_id":1,"installs.status":1}).explain() 

возвращает

{ 
     "cursor" : "BtreeCursor installs.reg_id_1_installs.status_1", 
     "isMultiKey" : true, 
     "n" : 1451589, 
     "nscannedObjects" : 2464985, 
     "nscanned" : 4373261, 
     "nscannedObjectsAllPlans" : 2464985, 
     "nscannedAllPlans" : 4373261, 
     "scanAndOrder" : false, 
     "indexOnly" : false, 
     "nYields" : 20170, 
     "nChunkSkips" : 0, 
     "millis" : 106353, 
     "indexBounds" : { 
       "installs.reg_id" : [ 
         [ 
           { 
             "$minElement" : 1 
           }, 
           { 
             "$maxElement" : 1 
           } 
         ] 
       ], 
       "installs.status" : [ 
         [ 
           1, 
           1 
         ] 
       ] 
     }, 
     "server" : "####:27017" 
} 

Здесь используется индекс соединения.

+0

вы можете включить еще одну объяснить - с намеком? Поэтому повторите запрос elemMatch, но после запроса, прежде чем объяснять() добавить .hint ({"installs.reg_id": 1, "installs.status": 1}) –

+0

@ АсяКамский Я обновил свой вопрос. спасибо, но все еще существует большая разница между 'n' и' nscanned'. Почему это, если индекс используется? – lovesh

+0

это из-за избирательности индекса (или его отсутствия). Я сочиняю полный ответ. –

ответ

2

Нет ничего плохого. Оптимизатор запросов выбирает индекс, который дает лучшую производительность/селективность.

Вы можете подтвердить это, «указав», что запрос использует индекс, который вы хотите использовать, и сравнивая количество элементов и документов, необходимых для сканирования, чтобы найти те, которые ему нужно вернуть.

Глядя на ваше объяснение, я вижу, что reg_id существует более чем на 92,5% записей индекса в индексе, который вы хотите использовать в своем запросе. Это не очень избирательно. Используя индекс, который вы хотите использовать, он сужает только 3.1M документы/записи до 2.9M - не очень хорошо.

Используя индекс status_1, он сразу сужает «кандидатов» до 1,7 млн., И теперь через все они обнаруживают, что у 1.4M есть reg_id.

Наличие более избирательных индексов является ключевым, но не забывайте, что в этом случае вы просите его вернуть документы 1.4M, поэтому трудно быть очень выборочным, когда это много документов необходимо отсканировать.

Другое дело - равенство, и это гораздо более эффективные операции для индексов (даже в равенстве), чем {$ существует}. Даже {$ ne: null} будет лучше, чем $ существует - в общем случае не стоит полагаться на запросы, которые используют $ exist или даже неравенства, чтобы быть такими, как равенство или запросы меньшего диапазона, могут быть (при использовании индексов) ,

Более подробную информацию можно найти здесь: http://docs.mongodb.org/manual/applications/indexes/ и, в частности, здесь: http://docs.mongodb.org/manual/tutorial/create-queries-that-ensure-selectivity/

+0

Так же создается индекс '{" installs.status ": 1, «installs.reg_id»: 1} 'улучшает производительность моего запроса? – lovesh

+0

не очень много. вы все еще смотрите на огромный набор результатов - даже если вы получите nscanned = n (число возвращено), оно не будет супер-быстрым ... может быть, другая схема будет более эффективной, но не зная других запросов и всех шаблонов записи сложно сказать. Возможно, что медленный запрос является результатом многих операций записи или медленного диска или недостаточно памяти ...? здесь недостаточно информации. –

1

У меня есть один и тот же вопрос. Это, как представляется, документированную ошибка, которая ориентирована на 2,7 (Из:/Aug/14 01) выпуска:

https://jira.mongodb.org/browse/SERVER-2348