programing

집계 프레임워크의 $198 및 $제한

newstyles 2023. 5. 4. 19:42

집계 프레임워크의 $198 및 $제한

문서를 읽었을 때 다음과 같은 참고 사항을 발견했습니다.

$sort가 파이프라인의 $limit 바로 앞에 있는 경우 $sort 작업은 진행됨에 따라 상위 n개의 결과만 유지합니다. 여기서 n은 지정된 제한이며 MongoDB는 메모리에 항목을 저장하기만 하면 됩니다.이 최적화는 allowDiskUse가 참이고 항목이 집계 메모리 제한을 초과하는 경우에도 적용됩니다.

만약 내가 이것에 대해 옳다면, $sort와 $limit을 같이 사용할 때만 적용됩니다.

db.coll.aggregate([
    ...,
    {$sort: ...},
    {$limit: limit},
    ...
]);

하지만, 대부분의 시간을 우리가 가질 것이라고 생각합니다.

db.coll.aggregate([
    ...,
    {$sort: ...},
    {$skip: skip},
    {$limit: limit},
    ...
]);

질문 1: $skip를 여기서 사용하면 위의 규칙이 적용되지 않는다는 뜻입니까?

이론적으로 MongoDB는 여전히 상위 n개의 레코드를 계산할 수 있고 상위 n개의 레코드만 정렬하여 성능을 향상시킬 수 있기 때문에 이 질문을 합니다.하지만 저는 이것에 대한 어떤 문서도 찾지 못했습니다.만약 규칙이 적용되지 않는다면,

질문 2: 성능을 향상시키려면 쿼리를 다음으로 변경해야 합니까?

db.coll.aggregate([
    ...,
    {$sort: ...},
    {$limit: skip + limit},
    {$skip: skip},
    {$limit: limit},
    ...
]);

편집: 제 사용 사례를 설명하면 위의 질문이 더 타당할 것 같습니다.MongoDB 2.6에서 제공하는 텍스트 검색 기능을 사용하여 제품을 찾고 있습니다.사용자가 "빨간색"과 같은 매우 일반적인 키워드를 입력하면 결과가 너무 많이 반환되지 않을까 걱정됩니다.따라서 저는 이 결과를 생성할 수 있는 더 나은 방법을 찾고 있습니다.

EDIT2: 위의 마지막 코드는 다음과 같습니다.

db.coll.aggregate([
    ...,
    {$sort: ...},
    {$limit: skip + limit},
    {$skip: skip},
    ...
]);

따라서 항상 이 양식을 사용하여 상위 N 규칙을 적용할 수 있습니다.

이것은 텍스트 검색 쿼리이므로 가장 적합한 형식은 다음과 같습니다.

db.collection.aggregate([
    { 
       "$match": {
               "$text": { "$search": "cake tea" }
    }
    },
    { "$sort": { "score": { "$meta": "textScore" } } },
    { "$limit": skip + limit },
    { "$skip": skip }
])

상위 "정렬" 결과의 메모리 예약에 대한 근거는 원래대로 자신의 "한계" 내에서만 작동하며, 이는 데이터의 몇 개의 합리적인 "페이지"를 초과하는 어떤 것에도 최적화되지 않습니다.

메모리 소비에 합리적인 수준을 넘어서면 추가 단계는 긍정적이기보다는 부정적인 영향을 미칠 가능성이 높습니다.

이것들은 실제로 현재 형태의 MongoDB에서 사용할 수 있는 텍스트 검색 기능의 실질적인 한계입니다.그러나 보다 세부적이고 성능이 더 요구되는 경우에는 대부분의 SQL "전체 텍스트" 솔루션과 마찬가지로 외부 "목적에 맞게 구축된" 텍스트 검색 솔루션을 사용하는 것이 좋습니다.

답변: $limit 앞에서 $skip

적어도 집계의 경우 $skip과 $limit의 순서는 확실히 중요합니다.그냥 해봤는데, 어떻게 빠졌는지 모르겠어요, 작전 이후로 바뀌었을 수도 있지만 공유하려고 생각했어요.

저는 이 대화에서 @vkarpov15의 의견에 동의합니다.

전체적으로 $limit은 다음 집계 상태로 전송되는 문서 수를 제한하고 $limit은 첫 번째 N개 문서를 건너뜁니다. 따라서 $limit이 $limit 이후이고 $limit > = $limit이면 결과를 얻을 수 없습니다.간단히 말해서, 이것은 MongoDB에서 예상되는 동작입니다.

제가 발견한 바에 따르면 이 사건은limit그리고.skip중요하지 않습니다.skip 앞에limit는 DB를 만들 입니다.limit 앞에skip후드 밑에

> db.system.profile.find().limit(1).sort( { ts : -1 } ).pretty()
{
    "op" : "command",
    "ns" : "archiprod.userinfos",
    "command" : {
        "aggregate" : "userinfos",
        "pipeline" : [
            {
                "$sort" : {
                    "updatedAt" : -1
                }
            },
            {
                "$limit" : 625
            },
            {
                "$skip" : 600
            }
        ],
    },
    "keysExamined" : 625,
    "docsExamined" : 625,
    "cursorExhausted" : true,
    "numYield" : 4,
    "nreturned" : 25,
    "millis" : 25,
    "planSummary" : "IXSCAN { updatedAt: -1 }",
    /* Some fields are omitted */
}

제가 를 켜면 요?$skip그리고.$limit도 같은 결과를 얻었습니다.keysExamined그리고.docsExamined.

> db.system.profile.find().limit(1).sort( { ts : -1 } ).pretty()
{
    "op" : "command",
    "ns" : "archiprod.userinfos",
    "command" : {
        "aggregate" : "userinfos",
        "pipeline" : [
            {
                "$sort" : {
                    "updatedAt" : -1
                }
            },
            {
                "$skip" : 600
            },
            {
                "$limit" : 25
            }
        ],
    },
    "keysExamined" : 625,
    "docsExamined" : 625,
    "cursorExhausted" : true,
    "numYield" : 5,
    "nreturned" : 25,
    "millis" : 71,
    "planSummary" : "IXSCAN { updatedAt: -1 }",
}

그리고 나서 저는 질문의 설명 결과를 확인했습니다.나는 그것을 발견했습니다.totalDocsExamined 미입니다.625에 시대에limit 무대.

> db.userinfos.explain('executionStats').aggregate([ { "$sort" : { "updatedAt" : -1 } }, { "$limit" : 625 }, { "$skip" : 600 } ])
{
    "stages" : [
        {
            "$cursor" : {
                "sort" : {
                    "updatedAt" : -1
                },
                "limit" : NumberLong(625),
                "queryPlanner" : {
                    "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "updatedAt" : -1
                            },
                            "indexName" : "updatedAt_-1",
                        }
                    },
                },
                "executionStats" : {
                    "executionSuccess" : true,
                    "nReturned" : 625,
                    "executionTimeMillis" : 22,
                    "totalKeysExamined" : 625,
                    "totalDocsExamined" : 625,
                    "executionStages" : {
                        "stage" : "FETCH",
                        "nReturned" : 625,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 625,
                        "advanced" : 625,
                        "docsExamined" : 625,
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "nReturned" : 625,
                            "works" : 625,
                            "advanced" : 625,
                            "keyPattern" : {
                                "updatedAt" : -1
                            },
                            "indexName" : "updatedAt_-1",
                            "keysExamined" : 625,
                        }
                    }
                }
            }
        },
        {
            "$skip" : NumberLong(600)
        }
    ]
}

그리고 놀랍게도, 저는 그것을 바꾸는 것을 발견했습니다.$skip그리고.$limit같은 결과를 낳습니다.explain결과.

> db.userinfos.explain('executionStats').aggregate([ { "$sort" : { "updatedAt" : -1 } }, { "$skip" : 600 }, { "$limit" : 25 } ])
{
    "stages" : [
        {
            "$cursor" : {
                "sort" : {
                    "updatedAt" : -1
                },
                "limit" : NumberLong(625),
                "queryPlanner" : {
                    /* Omitted */
                },
                "executionStats" : {
                    "executionSuccess" : true,
                    "nReturned" : 625,
                    "executionTimeMillis" : 31,
                    "totalKeysExamined" : 625,
                    "totalDocsExamined" : 625,
                    /* Omitted */
                }
            }
        },
        {
            "$skip" : NumberLong(600)
        }
    ]
}

보시다시피, 제가 지정한 것은$skip 앞에$limit에서, 서에explain결과는 여전히$limit 앞에$skip.

간단히 말해서, 저는 그것이 중요하지 않다는 결론에 도달했습니다.쿼리에 필터가 없다고 가정하고, 먼저 10개의 문서를 건너뛴 다음 5개의 문서로 제한합니다. 설명이 있으면 쿼리는 마지막 5개의 문서를 반환하고 총 15개의 문서를 검사합니다.제 분석을 판단해 주세요.

언급URL : https://stackoverflow.com/questions/24160037/skip-and-limit-in-aggregation-framework