2016-11-30 3 views
3

Я работаю с базой данных, которая имеет следующий дизайн документа:Правильно индексировать поле массива?

{ 
    'email': '[email protected]', 
    'credentials': [{ 
     'type':  'password', 
     'content': 'hashedpassword' 
    }, { 
     'type':  'oauth2', 
     'content': 'token' 
    }] 
} 

Я индексировали {credentials.type: 1, credentials.content: 1}. Он правильно подобрался, но производительность плоха в коллекции документов 50 тыс.

Вот лог с указанием плана запроса:

[conn73] command database.users command: find { 
    find: "users", 
    filter: { 
     credentials.type: "type", 
     credentials.content: "content" 
    }, 
    limit: 1, 
    batchSize: 1, 
    singleBatch: true 
} 
planSummary: IXSCAN { 
    credentials.type: 1, 
    credentials.content: 1 
} 
keysExamined:20860 
docsExamined:18109 
cursorExhausted:1 
keyUpdates:0 
writeConflicts:0 
numYields:163 
nreturned:1 
reslen:455 
locks:{ 
    Global: { 
     acquireCount: { 
      r: 328 
     } 
    }, 
    Database: { 
     acquireCount: { 
      r: 164 
     } 
    }, 
    Collection: { 
     acquireCount: { 
      r: 164 
     } 
    } 
} 
protocol:op_query 
331ms 

я заметил, у меня есть большое количество keysExamined и docsExamined. Я понимаю, что mongodb способен помещать все значения в массив для создания этого индекса. Зачем ему сканировать столько ключей?

У меня есть высокий одновременный доступ, но только для чтения.

Ниже объяснить() результат запроса:

> db.users.find({'credentials.type': 'abc', 'credentials.content': 'def'}).explain() 
{ 
    "queryPlanner" : { 
     "plannerVersion" : 1, 
     "namespace" : "net.users", 
     "indexFilterSet" : false, 
     "parsedQuery" : { 
      "$and" : [ 
       { 
        "credentials.type" : { 
         "$eq" : "abc" 
        } 
       }, 
       { 
        "credentials.content" : { 
         "$eq" : "def" 
        } 
       } 
      ] 
     }, 
     "winningPlan" : { 
      "stage" : "FETCH", 
      "filter" : { 
       "credentials.content" : { 
        "$eq" : "def" 
       } 
      }, 
      "inputStage" : { 
       "stage" : "IXSCAN", 
       "keyPattern" : { 
        "credentials.type" : 1, 
        "credentials.content" : 1 
       }, 
       "indexName" : "credentials.type_1_credentials.content_1", 
       "isMultiKey" : true, 
       "isUnique" : false, 
       "isSparse" : false, 
       "isPartial" : false, 
       "indexVersion" : 1, 
       "direction" : "forward", 
       "indexBounds" : { 
        "credentials.type" : [ 
         "[\"abc\", \"abc\"]" 
        ], 
        "credentials.content" : [ 
         "[MinKey, MaxKey]" 
        ] 
       } 
      } 
     }, 
     "rejectedPlans" : [ ] 
    }, 
    "serverInfo" : { 
     "host" : "localhost", 
     "port" : 27017, 
     "version" : "3.2.11", 
     "gitVersion" : "009580ad490190ba33d1c6253ebd8d91808923e4" 
    }, 
    "ok" : 1 
} 

Я бегу MongoDB v3.2.11. Как правильно оптимизировать этот запрос? Должен ли я изменить дизайн документа?

+0

и существующий указатель {credentials.type: 1, credentials.content: 1}, вы можете иметь индекс на {credentials: 1} –

+0

Можете ли вы подробнее рассказать о своем запросе и желаемых результирующих документах? также, пожалуйста, напишите запрос.explain() – sergiuz

+0

@SergiuZaharie. Я обновил, чтобы включить запрос. –

ответ

0

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

, такие как:

{ 
    'email': '[email protected]', 
    'credentialType':  'password', 
    'credentialContent': 'hashedpassword' 
} 

{ 
    'email': '[email protected]', 
    'credentialType':  'oauth2', 
    'credentialContent': 'token' 
} 

и создавать индексы credentialType и credentialContent.

Таким образом, у вас будет больше документа, но более четкие индексы. запрос будет работать быстрее. Потому что ему не нужно иметь дело с массивом obj.

+0

Есть ли ссылка на то, как индексы объектов массива должны быть медленными? –

0

Благодаря подсказке Серджиу Захари, я могу пересмотреть проблему с индексом.

Оказалось, что из-за «credentials.type» все схожие, и «credentials.content» все разные, я должен сначала добавить составной индекс в «credentials.content».

Иными словами, {credentials.content: 1, credentials.type: 1} является ответом здесь.

+0

Порядок полей в запросе не имеет значения при использовании индекса compund, это имеет значение только при сортировке. примеры здесь https://docs.mongodb.com/v3.2/tutorial/sort-results-with-indexes/#sort-and-non-prefix-subset-of-an-index – sergiuz

+0

Похоже, что индексирование по уникальной поле приводит к лучшей производительности, чем индексация на поле с несколькими вариантами выбора. Первоначально я думал, что порядок не имеет значения, и я не узнал иначе в другом месте. Я предположил, что проиндексированные поля объединены, но это тоже не так. Похоже, что первое поле в индексе очень важно, и лучше быть близким к уникальному. –

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