programing

MongoDB가 500만 개 이상의 레코드에 대해 성능을 조회합니다.

javamemo 2023. 3. 21. 21:25
반응형

MongoDB가 500만 개 이상의 레코드에 대해 성능을 조회합니다.

델은 최근 메인 컬렉션 중 하나로 200만 이상의 레코드를 달성했습니다.그리고 그 컬렉션의 퍼포먼스 문제로 어려움을 겪기 시작했습니다.

컬렉션의 문서에는 UI를 사용하여 필터링할 수 있는 약 8개의 필드가 있으며, 결과는 레코드가 처리된 타임스탬프 필드에 따라 정렬됩니다.

필터링된 필드와 시간표가 포함된 여러 복합 인덱스를 추가했습니다. 예:

db.events.ensureIndex({somefield: 1, timestamp:-1})

또한 성능 향상을 위해 여러 필터를 동시에 사용할 수 있는 인덱스를 몇 개 추가했습니다.그러나 일부 필터는 여전히 수행에 매우 오랜 시간이 걸립니다.

쿼리는 제가 만든 인덱스를 사용하지만 성능은 여전히 충분하지 않다는 것을 설명하도록 했습니다.

이제 샤딩이 좋은 방법인지 궁금해서..하지만 곧 그 컬렉션에서 매일 약 100만 장의 새로운 음반이 나오기 시작할 것입니다.잘 확장될지 모르겠지만

EDIT: 쿼리 예시:

> db.audit.find({'userAgent.deviceType': 'MOBILE', 'user.userName': {$in: ['nickey@acme.com']}}).sort({timestamp: -1}).limit(25).explain()
{
        "cursor" : "BtreeCursor user.userName_1_timestamp_-1",
        "isMultiKey" : false,
        "n" : 0,
        "nscannedObjects" : 30060,
        "nscanned" : 30060,
        "nscannedObjectsAllPlans" : 120241,
        "nscannedAllPlans" : 120241,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 1,
        "nChunkSkips" : 0,
        "millis" : 26495,
        "indexBounds" : {
                "user.userName" : [
                        [
                                "nickey@acme.com",
                                "nickey@acme.com"
                        ]
                ],
                "timestamp" : [
                        [
                                {
                                        "$maxElement" : 1
                                },
                                {
                                        "$minElement" : 1
                                }
                        ]
                ]
        },
        "server" : "yarin:27017"
}

deviceType은 제 컬렉션에 2개의 값만 있습니다.

이것은 건초더미에서 바늘을 뒤지는 것이다.explain()잘 수행되지 않는 쿼리에 대해 설명합니다.아쉽게도 이 경우에도 특정 쿼리에 대해서만 문제가 해결됩니다.이러한 접근법에 대한 전략은 다음과 같습니다.

  1. 메모리 부족이나 과도한 페이징이 원인이 아님을 확인
  2. 유효하게 합니다( 를 사용합니다).db.setProfilingLevel(1, timeout)서 ''는timeout쿼리 또는 명령어가 걸리는 시간(밀리초)의 임계값입니다.더 느린 것은 로그에 기록됩니다).
  3. 합니다.db.system.profile를 사용하여 합니다.explain()
  4. .explain(): ")scanAndOrder 큼직큼직큼직함nscanned 등등.
  5. 쿼리의 선택성과 인덱스를 사용하여 쿼리를 개선할 수 있는지 여부입니다.그렇지 않은 경우 최종 사용자에 대한 필터 설정을 허용하지 않거나 작업이 느릴 수 있다는 경고 대화 상자를 제공하는 것이 좋습니다.

중요한 문제는 사용자가 필터를 마음대로 조합할 수 있도록 허용하고 있다는 것입니다.인덱스 교차가 없으면 필요한 인덱스의 수가 대폭 증가합니다.

또한 가능한 모든 질의에 대해 무작정 색인을 던지는 것은 매우 나쁜 전략입니다.쿼리를 구성하고 인덱스된 필드에 충분한 선택성이 있는지 확인하는 것이 중요합니다.

모든 가정해 .status'무엇보다'그러나 500만 사용자 중 300만 명이 활성화되어 있고 200만 명이 활성화되어 있지 않기 때문에 500만 명이 넘는 엔트리는 두 가지 값밖에 없습니다.을 사용하다먼저 다른 기준을 검색한 다음 결과를 스캔하는 것이 좋습니다.평균적으로 100개의 문서를 반환할 때 167개의 문서를 스캔해야 하므로 성능이 크게 저하되지 않습니다.하지만 그렇게 간단하지 않아요.주요 기준이 다음과 같은 경우joined_at사용자의 날짜 및 시간이 지남에 따라 사용을 중단할 가능성이 높기 때문에 100개의 일치 항목을 찾기 전에 수천 개의 문서를 스캔해야 할 수 있습니다.

따라서 최적화는 데이터(구조뿐만 아니라 데이터 자체), 내부 상관 관계 및 쿼리 패턴에 따라 크게 달라집니다.

RAM에 비해 데이터가 너무 크면 상황이 더 악화됩니다. 인덱스를 사용하면 매우 좋지만, 결과를 스캔(또는 단순히 반환)하려면 디스크에서 많은 데이터를 랜덤으로 가져와야 할 수 있기 때문에 시간이 많이 걸릴 수 있습니다.

이를 제어하는 가장 좋은 방법은 서로 다른 쿼리 유형의 수를 제한하고 낮은 선택도 정보에 대한 쿼리를 허용하지 않으며 오래된 데이터에 대한 랜덤 액세스를 방지하는 것입니다.

의 모든 의 검색 후 를 사용하여 를 얻는 것이 .$in하지만 그것은 그 자체의 위험으로 가득 차 있다.

--편집 --

투고하신 설명은 낮은 선택도 필드의 스캔에 관한 문제의 아름다운 예입니다.nickey@acme.com에는 많은 자료가 있대요.이러한 문서를 찾아 타임스탬프별로 정렬하는 것은 선택성이 높은 인덱스에서 지원되기 때문에 매우 빠릅니다.안타깝게도 두 종류의 기기만 있기 때문에 mongo는 30060개의 문서를 스캔하여 '모바일'과 일치하는 첫 번째 기기를 찾아야 합니다.

이것은 웹 트래킹의 일종이라고 생각합니다만, 유저의 사용 패턴에 의해서 문의가 늦어집니다(매일 모바일과 웹을 바꾸면 문의가 빠릅니다).

이 특정 쿼리를 더 빠르게 하는 것은 장치 유형을 포함하는 복합 인덱스를 사용하여 수행할 수 있습니다(예: 사용).

a) ensureIndex({'username': 1, 'userAgent.deviceType' : 1, 'timestamp' :-1})

또는

b) ensureIndex({'userAgent.deviceType' : 1, 'username' : 1, 'timestamp' :-1})

불행하게도, 그것은 다음과 같은 질문들이find({"username" : "foo"}).sort({"timestamp" : -1}); 동일한 인덱스를 더 이상 사용할 없으므로 설명한 바와 같이 인덱스 수는 매우 빠르게 증가할 것입니다.

유감스럽게도 현재 mongodb를 사용하는 것은 좋은 해결책이 없습니다.

Mongo는 쿼리당 인덱스를 1개만 사용합니다.따라서 2개의 필드로 필터링할 경우 mongo는 하나의 필드와 함께 인덱스를 사용하지만 서브셋 전체를 스캔해야 합니다.

즉, 최상의 성능을 얻으려면 기본적으로 모든 유형의 쿼리에 대한 인덱스가 필요합니다.

데이터에 따라서는 필드당 하나의 쿼리를 가지고 앱에서 결과를 처리하는 것도 나쁘지 않을 수 있습니다.이렇게 하면 모든 필드에 인덱스만 필요하지만 처리하기에는 데이터가 너무 많을 수 있습니다.

$in을 사용하는 경우 mongodb는 INDEX를 사용하지 않습니다.이 $in을 제거하여 쿼리를 변경하십시오.인덱스를 사용해야 하며 이전에 받은 것보다 더 나은 성능을 제공할 수 있습니다.

http://docs.mongodb.org/manual/core/query-optimization/

언급URL : https://stackoverflow.com/questions/19559405/mongodb-querying-performance-for-over-5-million-records

반응형