MongoDB에서 느린 쿼리 진단 및 해결: 실용적인 가이드
MongoDB에서 느린 쿼리를 진단하고 해결하는 기술을 마스터하세요. 이 실용적인 가이드는 데이터베이스 프로파일러를 사용하여 병목 현상을 식별하고 강력한 `explain()` 메서드를 활용하여 실행 계획을 분석하는 방법을 알려줍니다. 성능을 최적화하고 NoSQL 데이터베이스가 최고의 효율로 작동하도록 보장하기 위해 ESR 규칙 및 커버링 인덱스 생성과 같은 필수 인덱싱 전략을 학습합니다.
MongoDB 느린 쿼리 진단 및 해결: 실전 가이드
MongoDB 느린 쿼리는 일반적으로 데이터가 증가하거나, 액세스 패턴이 변경되거나, 인덱스가 애플리케이션의 데이터 읽기 방식과 더 이상 일치하지 않을 때 나타납니다. 트래픽은 정상으로 보이는데 API 엔드포인트가 타임아웃되거나, 대시보드 로딩이 느려지거나, CPU 및 디스크 I/O가 상승하는 것을 경험할 수 있습니다.
프로파일러를 사용하여 느린 작업을 찾고, explain()을 사용하여 MongoDB가 어떻게 실행하는지 확인한 후, 대상 인덱스를 통해 MongoDB가 수행해야 하는 작업을 줄이십시오.
쿼리가 느려지는 이유 이해하기
인덱스를 변경하기 전에 일반적인 원인을 확인하십시오:
- 인덱스 누락 또는 비효율성: 유용한 인덱스가 없으면 MongoDB는 컬렉션 스캔을 수행하여 모든 문서를 검사할 수 있습니다.
- 쿼리 복잡성: 집계 단계, 대규모 정렬 또는 컬렉션 간 조회가 필요한 작업은 최적화되지 않으면 본질적으로 느릴 수 있습니다.
- 데이터 볼륨: 인덱싱된 쿼리라도 데이터셋이 방대하고 필터링 전에 수백만 개의 문서를 처리해야 하는 경우 속도가 느려질 수 있습니다.
- 하드웨어 제약: RAM 부족(광범위한 디스크 스와핑 유발) 또는 느린 디스크 I/O는 모든 작업의 성능을 저하시킬 수 있습니다.
1단계: 프로파일링을 사용하여 느린 쿼리 식별
해결의 첫 번째 단계는 식별입니다. MongoDB의 Database Profiler는 데이터베이스 작업의 실행 시간을 기록하여 정확히 어떤 쿼리가 문제를 일으키는지 파악할 수 있게 해줍니다.
프로파일러 활성화 및 구성
프로파일러는 다양한 수준에서 작동합니다. 레벨 0은 프로파일링을 비활성화합니다. 레벨 1은 구성된 임계값보다 느린 작업을 기록합니다. 레벨 2는 모든 작업을 기록합니다.
느린 쿼리를 분석하려면 일반적으로 50밀리초와 같은 임계값으로 레벨 1을 설정합니다:
// 프로파일링할 데이터베이스로 전환
use myDatabase
// 50밀리초보다 오래 걸리는 작업 캡처
db.setProfilingLevel(1, { slowms: 50 })
프로파일러 결과 검토
기록된 느린 작업은 system.profile 컬렉션에 저장됩니다. 이 컬렉션을 쿼리하여 최근 느린 쿼리를 확인할 수 있습니다:
// 50ms보다 오래 걸리는 작업 찾기
db.system.profile.find({ ns: "myDatabase.myCollection", millis: { $gt: 50 } }).sort({ ts: -1 }).limit(10).pretty()
레벨 2는 짧은 조사 목적으로만 유지하십시오. 모든 작업을 기록하므로 바쁜 프로덕션 데이터베이스에 오버헤드를 추가할 수 있습니다.
2단계: explain()을 사용한 쿼리 실행 분석
느린 쿼리를 식별한 후 explain()을 사용하여 MongoDB가 어떻게 처리하는지 확인하십시오.
explain('executionStats') 사용하기
executionStats 상세 수준은 실제 실행 시간 및 리소스 사용량을 포함하여 가장 포괄적인 출력을 제공합니다.
users 컬렉션을 대상으로 하는 다음 느린 쿼리를 고려하십시오:
db.users.find({ status: "active", city: "New York" }).sort({ registrationDate: -1 }).explain('executionStats')
출력 해석
explain() 출력에서 검사해야 할 주요 필드는 다음과 같습니다:
| 필드 | 설명 | 느림의 지표 |
|---|---|---|
winningPlan 단계 |
옵티마이저가 선택한 실행 계획. | COLLSCAN, 차단 SORT 또는 예상치 못한 인덱스를 찾으십시오. |
executionStats.nReturned |
작업에 의해 반환된 문서 수. | 적은 결과를 예상할 때 높은 숫자는 초기 필터링이 좋지 않음을 나타냅니다. |
executionStats.totalKeysExamined |
확인된 인덱스 키 수. | 인덱스가 효과적으로 사용되는 경우 일반적으로 nReturned에 가까워야 합니다. |
executionStats.totalDocsExamined |
디스크/메모리에서 실제로 검색된 문서 수. | 높은 숫자는 인덱스가 충분히 선택적이지 않았음을 시사합니다. |
executionStats.executionTimeMillis |
실행에 소요된 총 시간. | 실제 지연 시간과 비교하십시오. |
위험 신호: COLLSCAN
승리 계획에 COLLSCAN이 포함된 경우 MongoDB가 컬렉션을 스캔한 것입니다. 이는 일반적으로 쿼리에 더 나은 인덱스가 필요하거나, 조건이 선택적이지 않거나, 쿼리 형태가 인덱스 사용을 방해함을 의미합니다.
3단계: 인덱스 전략 구현
COLLSCAN 해결은 일반적으로 쿼리 패턴과 일치하도록 인덱스를 생성하거나 조정하는 것을 포함합니다.
복합 인덱스 생성
동등 일치, 범위 필터 또는 정렬과 같은 여러 필드가 포함된 쿼리의 경우 복합 인덱스가 필요한 경우가 많습니다. 일반적인 ESR 지침은 복합 인덱스 필드를 동등 조건자, 정렬 필드, 범위 조건자 순서로 정렬합니다. 이는 실제 쿼리 및 데이터로 테스트하는 것을 대체하는 지침이 아닙니다.
예시 시나리오:
쿼리: db.orders.find({ status: "PENDING", customerId: 123 }).sort({ orderDate: -1 })
ESR에 따라 인덱스는 다음 구조를 따라야 합니다:
- 동등 조건자 (
status,customerId) - 정렬 조건자 (
orderDate)
인덱스 생성:
db.orders.createIndex( { status: 1, customerId: 1, orderDate: -1 } )
이 인덱스를 사용하면 MongoDB가 상태와 고객 ID로 빠르게 필터링한 다음 orderDate로 이미 정렬된 결과를 효율적으로 검색할 수 있습니다.
정렬 작업 처리
explain()이 많은 문서를 검사한 후 차단 SORT 단계를 표시하는 경우 MongoDB가 인덱스를 사용하여 정렬된 결과를 반환할 수 없었습니다.
대규모 정렬은 메모리를 소비할 수 있으며 서버 버전 및 명령 옵션에 따라 디스크로 넘칠 수 있습니다. 더 나은 해결책은 일반적으로 필터와 정렬을 모두 지원하는 인덱스입니다.
.sort() 절에 사용된 필드가 적절한 복합 인덱스의 후행 요소로 있는지 확인하십시오.
4단계: 고급 최적화 기술
인덱싱만으로 느림이 해결되지 않는 경우 다음 고급 단계를 고려하십시오:
프로젝션 최적화
.find()의 두 번째 인수인 프로젝션을 사용하여 애플리케이션에 필요한 필드만 반환하십시오. 이렇게 하면 네트워크 전송이 줄어들고 프로젝션된 필드가 인덱스에 있는 경우 커버된 쿼리를 활성화할 수 있습니다.
// _id, name 및 email 필드만 반환
db.users.find({ city: "Boston" }, { name: 1, email: 1, _id: 1 })
커버링 인덱스
커버링 인덱스는 궁극적인 성능 목표입니다. 이는 쿼리(필터, 프로젝션 및 정렬)에 필요한 모든 필드가 인덱스 자체 내에 존재할 때 발생합니다. 이렇게 되면 MongoDB는 실제 문서를 가져올 필요가 없습니다(COLLSCAN이 방지되고 totalDocsExamined는 0 또는 매우 낮아짐).
explain() 출력에서 커버링 인덱스는 단계가 IXSCAN을 표시하고 totalDocsExamined가 0인 결과를 초래합니다.
하드웨어 및 구성 검토
totalKeysExamined와 totalDocsExamined가 합리적으로 보이지만 지연 시간이 여전히 높은 경우 쿼리 형태를 넘어 살펴보십시오. 작업 세트가 메모리에 맞는지, 디스크 지연 시간이 높은지, 서버가 쓰기 압력, 잠금 경합 또는 CPU 포화 상태에 있는지 확인하십시오.
핵심 요점
MongoDB 느린 쿼리 진단은 루프입니다: 워크로드 프로파일링, 느린 쿼리 설명, 인덱스 추가 또는 조정, 그리고 다시 측정. 좋은 수정은 검사된 문서를 낮추고, 피할 수 있는 컬렉션 스캔이나 차단 정렬을 제거하며, 사용자가 느끼는 실제 요청 경로를 개선합니다.
실행 가능한 체크리스트:
- 느린 쿼리를 캡처하기 위해 프로파일러를 임시로 활성화하십시오(
slowms). explain('executionStats')를 사용하여 문제가 있는 쿼리를 실행하십시오.COLLSCAN또는 높은totalDocsExamined를 확인하십시오.- ESR 규칙에 따라 필터와 정렬을 커버하도록 복합 인덱스를 생성하거나 수정하십시오.
explain()명령을 다시 실행하여 개선 사항을 확인하십시오.