2017-02-21 1 views
2

mongo 3.2.9 설치를 사용하여 일부 실시간 데이터 조사를 수행했습니다. 주요 요점은 문서 내에 데이터가 누락 된 레코드에 대한 세부 정보를 찾는 것이 었습니다. 그러나 내가 실행하고 있던 쿼리는 robomongo와 compass에서 시간 초과되었습니다.

저는 300 만 개가 넘는 레코드가 포함 된 모음집 (foo)이 있습니다. 나는 barId이없는 모든 레코드를 찾고 있어요,이게 내가 몽고에서 발사하고있는 쿼리입니다 다음 몽고에서

db.foo.find({barId:{$exists:true}}).explain(true) 

이 실행 계획 (인 쉘을 robomongo 또는 나침반 그것을 밖으로 배)

그것은 단지

2. 내가 유사한 쿼리를 실행하지만 반환하기 위해 내 barId_1 인덱스를 사용하고 있지만 동시에 그 모두 300 만 기록을 스캔과 같은

MongoDB Enterprise > db.foo.find({barId:{$exists:true}}).explain(true) 
{ 
    "queryPlanner" : { 
    "plannerVersion" : 1, 
    "namespace" : "myDatabase01.foo", 
    "indexFilterSet" : false, 
    "parsedQuery" : { 
     "barId" : { 
     "$exists" : true 
     } 
    }, 
    "winningPlan" : { 
     "stage" : "FETCH", 
     "filter" : { 
     "barId" : { 
      "$exists" : true 
     } 
     }, 
     "inputStage" : { 
     "stage" : "IXSCAN", 
     "keyPattern" : { 
      "barId" : 1 
     }, 
     "indexName" : "barId_1", 
     "isMultiKey" : false, 
     "isUnique" : false, 
     "isSparse" : false, 
     "isPartial" : false, 
     "indexVersion" : 1, 
     "direction" : "forward", 
     "indexBounds" : { 
      "barId" : [ 
      "[MinKey, MaxKey]" 
      ] 
     } 
     } 
    }, 
    "rejectedPlans" : [ ] 
    }, 
    "executionStats" : { 
    "executionSuccess" : true, 
    "nReturned" : 2, 
    "executionTimeMillis" : 154716, 
    "totalKeysExamined" : 3361040, 
    "totalDocsExamined" : 3361040, 
    "executionStages" : { 
     "stage" : "FETCH", 
     "filter" : { 
     "barId" : { 
      "$exists" : true 
     } 
     }, 
     "nReturned" : 2, 
     "executionTimeMillisEstimate" : 152060, 
     "works" : 3361041, 
     "advanced" : 2, 
     "needTime" : 3361038, 
     "needYield" : 0, 
     "saveState" : 27619, 
     "restoreState" : 27619, 
     "isEOF" : 1, 
     "invalidates" : 0, 
     "docsExamined" : 3361040, 
     "alreadyHasObj" : 0, 
     "inputStage" : { 
     "stage" : "IXSCAN", 
     "nReturned" : 3361040, 
     "executionTimeMillisEstimate" : 1260, 
     "works" : 3361041, 
     "advanced" : 3361040, 
     "needTime" : 0, 
     "needYield" : 0, 
     "saveState" : 27619, 
     "restoreState" : 27619, 
     "isEOF" : 1, 
     "invalidates" : 0, 
     "keyPattern" : { 
      "barId" : 1 
     }, 
     "indexName" : "barId_1", 
     "isMultiKey" : false, 
     "isUnique" : false, 
     "isSparse" : false, 
     "isPartial" : false, 
     "indexVersion" : 1, 
     "direction" : "forward", 
     "indexBounds" : { 
      "barId" : [ 
      "[MinKey, MaxKey]" 
      ] 
     }, 
     "keysExamined" : 3361040, 
     "dupsTested" : 0, 
     "dupsDropped" : 0, 
     "seenInvalidated" : 0 
     } 
    }, 
    "allPlansExecution" : [ ] 
    }, 
    "serverInfo" : { 
    "host" : "myLinuxMachine", 
    "port" : 8080, 
    "version" : "3.2.9", 
    "gitVersion" : "22ec9e93b40c85fc7cae7d56e7d6a02fd811088c" 
    }, 
    "ok" : 1 
} 

아니라 필드의 존재를 찾는 것보다 0보다 큰 ID를 찾았습니다 (모두)

MongoDB Enterprise > db.foo.find({barId:{$gt:"0"}}).explain(true) 
{ 
    "queryPlanner" : { 
    "plannerVersion" : 1, 
    "namespace" : "myDatabase01.foo", 
    "indexFilterSet" : false, 
    "parsedQuery" : { 
     "barId" : { 
     "$gt" : "0" 
     } 
    }, 
    "winningPlan" : { 
     "stage" : "FETCH", 
     "inputStage" : { 
     "stage" : "IXSCAN", 
     "keyPattern" : { 
      "barId" : 1 
     }, 
     "indexName" : "barId_1", 
     "isMultiKey" : false, 
     "isUnique" : false, 
     "isSparse" : false, 
     "isPartial" : false, 
     "indexVersion" : 1, 
     "direction" : "forward", 
     "indexBounds" : { 
      "barId" : [ 
      "(\"0\", {})" 
      ] 
     } 
     } 
    }, 
    "rejectedPlans" : [ ] 
    }, 
    "executionStats" : { 
    "executionSuccess" : true, 
    "nReturned" : 2, 
    "executionTimeMillis" : 54, 
    "totalKeysExamined" : 2, 
    "totalDocsExamined" : 2, 
    "executionStages" : { 
     "stage" : "FETCH", 
     "nReturned" : 2, 
     "executionTimeMillisEstimate" : 10, 
     "works" : 3, 
     "advanced" : 2, 
     "needTime" : 0, 
     "needYield" : 0, 
     "saveState" : 0, 
     "restoreState" : 0, 
     "isEOF" : 1, 
     "invalidates" : 0, 
     "docsExamined" : 2, 
     "alreadyHasObj" : 0, 
     "inputStage" : { 
     "stage" : "IXSCAN", 
     "nReturned" : 2, 
     "executionTimeMillisEstimate" : 10, 
     "works" : 3, 
     "advanced" : 2, 
     "needTime" : 0, 
     "needYield" : 0, 
     "saveState" : 0, 
     "restoreState" : 0, 
     "isEOF" : 1, 
     "invalidates" : 0, 
     "keyPattern" : { 
      "barId" : 1 
     }, 
     "indexName" : "barId_1", 
     "isMultiKey" : false, 
     "isUnique" : false, 
     "isSparse" : false, 
     "isPartial" : false, 
     "indexVersion" : 1, 
     "direction" : "forward", 
     "indexBounds" : { 
      "barId" : [ 
      "(\"1\", {})" 
      ] 
     }, 
     "keysExamined" : 2, 
     "dupsTested" : 0, 
     "dupsDropped" : 0, 
     "seenInvalidated" : 0 
     } 
    }, 
    "allPlansExecution" : [ ] 
    }, 
    "serverInfo" : { 
    "host" : "myLinuxMachine", 
    "port" : 8080, 
    "version" : "3.2.9", 
    "gitVersion" : "22ec9e93b40c85fc7cae7d56e7d6a02fd811088c" 
    }, 
    "ok" : 1 
} 

다시 barId_1의 인덱스 스캔을 수행했습니다. 2를 반환하는 2 개의 레코드를 스캔했습니다.

완전성을 위해 여기에 2 개의 레코드가 있고 다른 3 백만 개의 크기와 구성은 매우 비슷합니다.

MongoDB Enterprise > db.foo.find({barId:{$gt:"0"}}) 
{ 
    "_id" : "00002f5d-ee4a-4996-bb27-b54ea84df777", "createdDate" : ISODate("2016-11-16T02:26:48.500Z"), "createdBy" : "Exporter", "lastModifiedDate" : ISODate("2016-11-16T02:26:48.500Z"), "lastModifiedBy" : "Exporter", "rolePlayed" : "LA", "roleType" : "T", "oId" : [ "d7316944-62ed-48dc-8ee4-e3bad8c58b10" ], "barId" : "e45b3160-bbb4-24e5-82b3-ad0c28329555", "cId" : "dcc29053-7a1f-439e-9536-fb4e44ff8a51", "timestamp" : "2017-02-20T16:23:15.795Z" 
} 
{ 
    "_id" : "00002f5d-ee4a-4996-bb27-b54ea84df888", "createdDate" : ISODate("2016-11-16T02:26:48.500Z"), "createdBy" : "Exporter", "lastModifiedDate" : ISODate("2016-11-16T02:26:48.500Z"), "lastModifiedBy" : "Exporter", "rolePlayed" : "LA", "roleType" : "T", "oId" : [ "d7316944-62ed-48dc-8ee4-e3bad8c58b10" ], "barId" : "e45b3160-bbb4-24e5-82b3-ad0c28329555", "cId" : "dcc29053-7a1f-439e-9536-fb4e44ff8a51", "timestamp" : "2017-02-20T16:23:15.795Z" 
} 

는 물론 좀 주위에 인터넷 검색을 수행하고이 절을 존재와 함께 인덱스를 사용하여 문제가있을 사용하는 것을 발견,하지만 많은 스레드에서 나는이 고정되어 읽었습니다. 그렇지? 또한 필드의 존재를 찾을 때 인덱스의 '올바른'사용을 강제하기 위해 $ exists 절 대신 사용할 수있는 다음과 같은 해킹을 발견했습니다.

MongoDB Enterprise > db.foo.find({barId:{$ne:null}}).explain(true) 
{ 
    "queryPlanner" : { 
    "plannerVersion" : 1, 
    "namespace" : "myDatabase01.foo", 
    "indexFilterSet" : false, 
    "parsedQuery" : { 
     "$not" : { 
     "barId" : { 
      "$eq" : null 
     } 
     } 
    }, 
    "winningPlan" : { 
     "stage" : "FETCH", 
     "filter" : { 
     "$not" : { 
      "barId" : { 
      "$eq" : null 
      } 
     } 
     }, 
     "inputStage" : { 
     "stage" : "IXSCAN", 
     "keyPattern" : { 
      "barId" : 1 
     }, 
     "indexName" : "barId_1", 
     "isMultiKey" : false, 
     "isUnique" : false, 
     "isSparse" : false, 
     "isPartial" : false, 
     "indexVersion" : 1, 
     "direction" : "forward", 
     "indexBounds" : { 
      "barId" : [ 
      "[MinKey, null)", 
      "(null, MaxKey]" 
      ] 
     } 
     } 
    }, 
    "rejectedPlans" : [ ] 
    }, 
    "executionStats" : { 
    "executionSuccess" : true, 
    "nReturned" : 2, 
    "executionTimeMillis" : 57, 
    "totalKeysExamined" : 3, 
    "totalDocsExamined" : 2, 
    "executionStages" : { 
     "stage" : "FETCH", 
     "filter" : { 
     "$not" : { 
      "barId" : { 
      "$eq" : null 
      } 
     } 
     }, 
     "nReturned" : 2, 
     "executionTimeMillisEstimate" : 10, 
     "works" : 4, 
     "advanced" : 2, 
     "needTime" : 1, 
     "needYield" : 0, 
     "saveState" : 0, 
     "restoreState" : 0, 
     "isEOF" : 1, 
     "invalidates" : 0, 
     "docsExamined" : 2, 
     "alreadyHasObj" : 0, 
     "inputStage" : { 
     "stage" : "IXSCAN", 
     "nReturned" : 2, 
     "executionTimeMillisEstimate" : 10, 
     "works" : 4, 
     "advanced" : 2, 
     "needTime" : 1, 
     "needYield" : 0, 
     "saveState" : 0, 
     "restoreState" : 0, 
     "isEOF" : 1, 
     "invalidates" : 0, 
     "keyPattern" : { 
      "barId" : 1 
     }, 
     "indexName" : "barId_1", 
     "isMultiKey" : false, 
     "isUnique" : false, 
     "isSparse" : false, 
     "isPartial" : false, 
     "indexVersion" : 1, 
     "direction" : "forward", 
     "indexBounds" : { 
      "barId" : [ 
      "[MinKey, null)", 
      "(null, MaxKey]" 
      ] 
     }, 
     "keysExamined" : 3, 
     "dupsTested" : 0, 
     "dupsDropped" : 0, 
     "seenInvalidated" : 0 
     } 
    }, 
    "allPlansExecution" : [ ] 
    }, 
    "serverInfo" : { 
    "host" : "myLinuxMachine", 
    "port" : 8080, 
    "version" : "3.2.9", 
    "gitVersion" : "22ec9e93b40c85fc7cae7d56e7d6a02fd811088c" 
    }, 
    "ok" : 1 
} 

이 방법은 스캔 된 문서가 2 개 뿐이며 2 개의 문서 만 반환됩니다.

내 질문에 따라서. 검색어에 $가 있어야합니까? 라이브 프로덕션 응용 프로그램에서 사용하기에 적합한 제품입니까? 대답이 '아니오'인 경우 왜 $ exist 절이 맨 처음에 존재합니까?

mongo의 설치가 잘못되었거나 색인이 어딘지 모를 가능성이 항상 있습니다. 어떤 빛이라도 환영 할 만하지만, 지금은 $ n : null 해킹을 고수하고 있습니다.

답변

2

당신은 사용해야합니다 (권장) 또는 barId 필드의 스파 스 인덱스 partial index이 완벽하게 일했다

db.foo.createIndex(
    { barId: 1 }, 
    { partialFilterExpression: { barId: { $exists: true } } } 
) 
+0

감사합니다. 제안 된 인덱스를 추가하면 barId를 실행하는 데 걸리는 시간이 단축됩니다. {$ exists : true} 10의 인수로 쿼리합니다. 인덱스의 차이에 대한 이유를 정말로 염려합니다. 왜 이런 모든 인덱스를 만들지 않습니까? – Damo