2016-11-30 104 views
3

我與具有以下文件設計數據庫工作:正確索引數組字段?

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

我已經索引{credentials.type: 1, credentials.content: 1}。它被正確地拾取,但是在50k文檔集合上表現糟糕。

這裏是指示查詢計劃日誌:

[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

您可以詳細說明您的查詢和所需的結果文檔嗎?也請發帖query.explain() – sergiuz

+0

@SergiuZaharie我已經更新,包括查詢解釋。 –

回答

0

您可以嘗試將憑據分爲不同的文檔。

如:

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

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

和創建credentialType和credentialContent指標。

這樣你會有更多的文檔,但更清晰的索引。你的查詢會運行得更快。因爲它不需要處理obj數組。

+0

有沒有關於數組對象索引應該如何慢的參考? –

0

感謝Sergiu Zaharie的提示,我能夠重新審視索引問題。

事實證明,由於'credentials.type'都是相似的,'credentials.content'都是不同的,我應該首先將複合索引放在'credentials.content'上。

換句話說,{credentials.content: 1, credentials.type: 1}就是這裏的答案。

+0

使用複合索引時,查詢中字段的順序無關緊要,它僅在排序上很重要。這裏的例子https://docs.mongodb.com/v3.2/tutorial/sort-results-with-indexes/#sort-and-non-prefix-subset-of-an-index – sergiuz

+0

它看起來像一個獨特的索引字段導致更好的性能比在一個有少量選擇的字段上索引。我原本以爲這個命令並不重要,我也沒有在其他地方學過。我認爲索引字段是連接的,但事實並非如此。看起來指數中的第一個領域非常重要,最好接近獨特。 –