MongoDB Optimizer 프로세스는 타 DBMS의 Optimizer와 다소 상이하고, 관련 포스트가 거의 없어서 프로세스를 파악하기 어렵다.
인터넷에 정리된 문서들과 MongoDB 소스코드를 참고하여 MongoDB의 Optimizer 프로세스를 이해해보자.
해당 포스트는 MongoDB Community Server 4.2를 기준으로 작성했으며, 버전에 따라 프로세스가 상이할수 있다.
MongoDB는 RDBMS와 비교했을 때 데이터베이스에 대한 통계정보가 거의 없는 수준이다.
따라서 RDBMS처럼 통계정보를 이용하여 쿼리 최적화를 수행할 수가 없고, 쿼리 형태와 사용 인덱스만 비교하며 Plan을 생성하는 다소 무식한 방법을 사용한다.
이로 인한 부정확성을 보완하기 위해 MongoDB는 특수한 Evaluating 과정을 수행하여 각 후보 플랜(Candidate Plan)에 점수를 부여한다.
가장 점수가 높은 Plan은 Winning Plan으로 선정되어 Plan Cache에 저장되고, 쿼리에 사용된다.
이후에 동일한 쿼리 형태가 들어오면 Plan Cache에 있는 플랜을 사용하여 쿼리 최적화 시간을 최소화하도록 동작한다.
일단 쿼리가 들어오면, MongoDB Optimizer는 Plan Cache에 매칭되는 Plan이 있는지 검색을 수행한다.
들어온 쿼리와 동일한 쿼리 형태에 대한 Plan을 Matching Plan으로 인식한다.
A. Plan Cache에 Matching Plan이 있는 경우
B. Plan Cache에 매칭 플랜이 없는 경우
프로세스를 수행한다.B. Plan Cache에 Matching Plan이 없는 경우
이 중 굵게 표시된 메인 프로세스들을 좀 더 자세히 살펴보자.
타 DBMS와 달리, MongoDB는 쿼리 Plan을 생성할 때 데이터베이스의 통계 정보를 전혀 사용하지 않는다.
오직 요청된 쿼리의 형태와 인덱스 목록만 보고 Plan을 생성한다.
MongoDB는 컬렉션의 인덱스 목록 중, 요청된 쿼리와 '연관된' 인덱스를 추출하여 Indexed Plan을 생성한다.
쿼리와 인덱스의 '연관성'을 판단하는 기준은 아래와 같다.
ㅤ
적절한 Indexed Plan이 없는 경우에는 COLLSCAN Plan을 생성한다.
다시 말해서, Indexed Plan이 하나라도 있으면 COLLSCAN이 더 효율적인 경우에도 COLLSCAN Plan은 생성되지 않는다는 의미이다.
🔗 2-1. Plan - Source Code(QueryPlanner::plan)
MongoDB는 옵티마이징에 다양한 데이터베이스 정보를 이용하지 못한다는 약점을 보완하기 위해, 모든 후보 플랜(Candidate Plan)을 동시에 조금씩 수행해보는 과정을 거친다.
반복문을 사용해 모든 Candidate Plan에 Work를 1회씩 호출하는데, 이 과정을 Working이라고 지칭하겠다.
Working은 아래 조건 중 하나를 만족할 때까지 반복적으로 수행된다.
- numWorks : (컬렉션의 데이터 개수 x 0.29) 와 10,000 중 큰 값
- numResults : limit() 파라미터와 101 중 작은 값
🔗 2.2 Work Candidate Plans - Source Code(MultiPlanStage::pickBestPlan)
🔗 2.2 Work Candidate Plans - Source Code(MultiPlanStage::workAllPlans)
Working이 완료된 플랜들은 아래 지표의 합으로 점수가 책정된다.
baseScore를 포함하는 이유는 아무 Plan도 선택되지 않는 No Plan Selected
가 0점의 score를 가지기 때문이다.
쿼리를 수행할 때 최대한 Plan을 사용하게 하기 위해 optimizer는 기본적으로 모든 Plan에 1점의 점수를 부여한다.
tieBreakers는 쿼리 플랜이 다음의 경우를 만족할 경우 각각 epsilon* 만큼 부여하는 보너스 점수를 의미한다.
- epsilon : ( 1 / ( 10 x workUnits ) ) 와 10-4 중 작은 값
EOF Bonus는 Winning Plan 선정 시에만 사용되고, Cache에 저장될 때는 점수에 포함되지 않는다.
캐싱된 Plan을 검증하는 과정에서 EOF Bonus를 얻지 못하면 실제 Plan의 효율과 관계 없이 evict될 확률이 높아지기 때문이다.
🔗 2-3. Pick Best Plan - Source Code(PlanRanker::scoreTree)
ㅤ
한번 생성된 쿼리 Plan은 Plan Cache에 저장되어 있다가, 아래의 경우에 Evict된다.
ㅤ
Optimizer가 쿼리 Plan의 효율성을 검증하는 방법은 아래와 같다.
- maxWorksBeforeReplan : 10 x decisionWorks*
- numResults : limit() 파라미터와 101 중 작은 값
- decisionWorks : the number of work cycle taken to decide on a winning plan when the plan was first cached
🔗 2-4. Evict Plan Cache Entry - Source Code(CachedPlanStage::pickBestPlan)
ㅤ
멋있어요~~