잡동사니

반응형

질문

쿼리가 있습니다 (매우 느린 ~ 2,5s ) :

db.markers.find({ latlng: { '$within': { '$box': [ [ -16, -140 ], [ 75, 140 ] ] } } }).sort({_id: -1}).limit(1000)

이 쿼리에 대한 설명을 실행하면

{
   "cursor" : "GeoBrowse-box",
   "isMultiKey" : false,
   "n" : 1000,
   "nscannedObjects" : 242331,
   "nscanned" : 242331,
   "nscannedObjectsAllPlans" : 242331,
   "nscannedAllPlans" : 242331,
   "scanAndOrder" : true,
   "indexOnly" : false,
   "nYields" : 1383,
    "nChunkSkips" : 0,
    "millis" : 2351,
    "indexBounds" : {
        "latlng" : [ ]
    },
    "lookedAt" : NumberLong(262221),
    "matchesPerfd" : NumberLong(242331),
    "objectsLoaded" : NumberLong(242331),
    "pointsLoaded" : NumberLong(0),
    "pointsSavedForYield" : NumberLong(0),
    "pointsChangedOnYield" : NumberLong(0),
    "pointsRemovedOnYield" : NumberLong(0),
    "server" : "xx:27017"
}

sort ({_ id : -1}) 를 제거하면 설명이 나에게 제공됩니다 (빠른 쿼리 5 밀리 ) :

{
    "cursor" : "GeoBrowse-box",
    "isMultiKey" : false,
    "n" : 1000,
    "nscannedObjects" : 1000,
    "nscanned" : 1000,
    "nscannedObjectsAllPlans" : 1000,
    "nscannedAllPlans" : 1000,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 5,
    "indexBounds" : {
        "latlng" : [ ]
    },
    "lookedAt" : NumberLong(1000),
    "matchesPerfd" : NumberLong(1000),
    "objectsLoaded" : NumberLong(1000),
    "pointsLoaded" : NumberLong(0),
    "pointsSavedForYield" : NumberLong(0),
    "pointsChangedOnYield" : NumberLong(0),
    "pointsRemovedOnYield" : NumberLong(0),
        "server" : "xx:27017"
}

latlng에 2d 인덱스, _id 및 compound 인덱스에 desc 인덱스가 있습니다.

db.markers.ensureIndex({latlng: '2d', _id:-1})
db.markers.ensureIndex({ latlng: '2d' })
db.markers.ensureIndex({ _id: -1 })

내가 달성하고 싶은 것은 최신에서 정렬 된 특정 영역에서 마커를 얻는 것입니다.

2.5 초 보다 훨씬 적은 작업을 수행하는 방법에 대한 아이디어 나 제안이 있습니까 ??

누군가 자신의 테스트를하고 싶다면

var i = 0,
  lat = 0,
  lng = 0;

for (i; i < 260000; i++) {
  lat = parseFloat(Math.min(-90 + (Math.random() * 180), 90).toFixed(6));
  lng = parseFloat(Math.min(-180 + (Math.random() * 360), 180).toFixed(6));
  collection.insert({latlng: [lat, lng]}, function () {});
}

collection.find({ latlng: { '$within': { '$box': [ [ -90, -180 ], [ 90, 180 ] ] } } }, {latlng: 1, _id: 1 }).sort({_id: -1}).limit(1000).explain()

내 로컬 컴퓨터에서 수신합니다 ( ~ 2,6s ).

{
    "cursor" : "GeoBrowse-box",
    "isMultiKey" : false,
    "n" : 1000,
    "nscannedObjects" : 260000,
    "nscanned" : 260000,
    "nscannedObjectsAllPlans" : 260000,
    "nscannedAllPlans" : 260000,
    "scanAndOrder" : true,
    "indexOnly" : false,
    "nYields" : 1612,
    "nChunkSkips" : 0,
    "millis" : 2613,
    "indexBounds" : {
            "latlng" : [ ]
    },
    "lookedAt" : NumberLong(260000),
    "matchesPerfd" : NumberLong(260000),
    "objectsLoaded" : NumberLong(260000),
    "pointsLoaded" : NumberLong(0),
    "pointsSavedForYield" : NumberLong(0),
    "pointsChangedOnYield" : NumberLong(0),
    "pointsRemovedOnYield" : NumberLong(0),
    "server" : "xx:27017"
}

고마워


답변1

실제로 컬렉션에 다음 세 가지 인덱스가 정의되어 있습니까?

db.markers.ensureIndex({ latlng: '2d', _id:-1 })
db.markers.ensureIndex({ latlng: '2d' })
db.markers.ensureIndex({ _id: -1 })

지리 공간 색인 생성 문서는 동일한 컬렉션에 여러 지역 색인을 만드는 것을 권장하지 않습니다. MongoDB가이를 허용하지만이 동작은 바람직하지 않을 수 있습니다. 귀하의 경우에 대한 제 생각에는 복합 색인 대신 사용하기 위해 비 복합 {latlng : '2d'} 가 선택되었을 수 있습니다. explain () 출력은 색인 이름 대신 GeoBrowse-box 를보고하기 때문에 여기에서 실제로 도움이되지 않습니다. 그러나 커서가 복합 색인을 사용하고 결과가 개선되는지 확인하기 위해 수동으로 힌트 를 제안합니다. . 또는 단순히 비 복합 색인을 제거하여 {latlng : '2d', _id : -1} 쿼리 최적화 프로그램을위한 명백하고 유일한 선택이기 때문입니다.

마지막으로 {_ id : -1} 색인은 중복되며 제거 할 수 있습니다. 복합 색인 문서에 따라 방향은 여러 필드로 구성된 색인을 다룰 때만 관련됩니다. 단일 키 인덱스의 경우 인덱스를 앞뒤로 충분히 쉽게 이동할 수 있습니다. MongoDB는 기본적으로 우리를 위해 이미 {_ id : 1} 인덱스를 생성하기 때문에 단순히 그것에 의존하는 것이 더 효율적입니다.

이제 인덱싱이 중단됩니다. 쿼리의 한 가지주의 사항은 비 지역 기준 ( _id )으로 정렬하기 전에 지리 공간 쿼리 component에 제한이 적용된다는 것입니다. 결과는 실제로 _id 로 정렬되지만 해당 정렬은 일치하는 범위 내의 모든 문서를 고려하지 않을 수 있음을 의미합니다. 이는 복합 색인 비트에 언급되어 있습니다. 보류중인 솔루션으로 https://jira.mongodb.org/browse/SERVER-4247">SERVER-4247 .


수정 : 벤치 마크 후속 조치

나는 ± 90과 ± 180 사이의 260k 랜덤 포인트 인 예제 데이터를 채웠다. 그런 다음 쿼리를 실행했습니다.

db.markers.find(
  { latlng: { $within: { $box: [[-90, -180], [90, 180]] }}},
  { latlng: 1, _id: 1 }
).sort({_id: -1}).limit(1000).explain()

1713ms가 걸렸습니다 (2351ms의 시간 대신 비교 기준으로 사용하겠습니다). 또한 쿼리가 26 만 개의 모든 문서와 일치하고 동일한 수의 인덱스 항목을 스캔했습니다. _id 정렬까지 제한이 고려되지 않았던 것 같습니다. 여기 . 그런 다음 다른 경우를 조사하기 위해 쿼리를 약간 수정했습니다.

  • _id 정렬 및 제한이없는 원래 쿼리 : nscanned 는 260k이고 시간은 1470ms입니다.
  • _id 정렬이없는 원래 쿼리 : nscanned 는 1000이고 시간은 9ms입니다.
  • 제한이없는 원래 쿼리 : nscanned 는 260k이고 시간은 2567ms입니다.

또한 색인화되지 않은 필드에서만 정렬을 테스트하여 지역 일치 후 _id 정렬에서 발생할 수있는 상황을 시뮬레이션하고 싶었습니다. 그러나 기본 색인이 항상 존재하므로 _id 를 사용할 수 없습니다. 이를 위해 복합 지리 색인을 삭제 한 다음 latlng 객체별로 정렬했습니다. 그 결과 260k의 nscanned 와 1039ms의 시간이 발생했습니다. 제한을 1000으로 추가하면 시간은 461ms입니다.

위의 1470ms (정렬 및 제한이없는 지리적 쿼리)에 추가하면 제한이없는 원래 쿼리 인 2567ms에 매우 가깝습니다. 마찬가지로, 461ms ( 제한된 정렬 )를 1470ms에 추가하면 원래 벤치 마크 결과 인 1713ms에 가깝습니다. 이 상관 관계를 바탕으로 벤치 마크의 _id 정렬이 복합 지수를 전혀 활용하지 않는다고 확신합니다.

어쨌든 벤치 마크가 느린 또 다른 이유는 매우 광범위한 지역 일치 때문입니다. 경계가 더 좁 으면 정렬이 색인화되지 않은 경우에도 정렬 할 데이터가 줄어들 것입니다. 즉, SERVER-4247 이 도움이 될 것이라고 생각합니다. 비 지역 정렬을 먼저 처리 할 가능성이 높기 때문입니다. 지역 일치를 수행하기 전에.



답변2

색인이 복합 키를 사용하고 있습니까?

db.markers.ensureIndex({latlng: '2d', _id:-1})


 

 

 

 

출처 : https://stackoverflow.com/questions/12908871/mongodb-geospatial-query-with-sort-performance-issues

반응형

이 글을 공유합시다

facebook twitter googleplus kakaoTalk kakaostory naver band