8. 인덱싱과 쿼리 최적화
8.1 인덱싱의 이론적 고찰
- 책의 목차와 같이 찾고자 하는 데이터를 빠르게 찾기 위한 것
- 단순 인덱스
- 단일 키에 대해 생성한 인덱스
- 복합 인덱스
- 둘 이상의 키를 사용하여 생성한 인덱스
- 키 순서 중요
- 인덱스 효율
- 인덱스에는 비용이 발생하니 조심히 생성
- 삽입 연산을 수행할 때 마다 새 도큐먼트가 인덱스가 포함되도록 수정
- 인덱스에는 비용이 발생하니 조심히 생성
8.2 인덱싱의 실제
8.2.1 인덱스 타입
- 인덱스에 B-트리 인덱스가 사용되며 몇가지 특성을 적용할 수 있음
- 고유 인덱스
- 필드의 해당 도큐먼트에 고유한 키임을 보장하기 위해 사용
- unique 옵션을 지정해서 사용
// 고유 인덱스 생성 db.users.createIndex({ username: 1}, { unique: true });
- 희소 인덱스
- null이 아닌 값에 대해 고유 인덱스를 설정하려고 할때 사용
- sparse 옵션 추가
db.products.createIndex({ sku: 1}, { unique: true, sparse: true });
- 다중키 인덱스
- 필드의 값이 배열인 경우 사용 가능한 인덱스
{ name: "Wheelbarrow", tags: ["tools", "gardening", "soil"] }
- 필드의 값이 배열인 경우 사용 가능한 인덱스
- 해시 인덱스
- 해시된 값이 순서를 결정
- 해시를 인덱스 정렬 방향으로 전달하여 생성
// 해시 인덱스 추가 db.recipes.createIndex({recipe_name: 'hashed'}); - 제한 사항
- 동등 쿼리는 거의 동이랗게 작동하지만 범위 쿼리는 지원 X
- 다중 키 해시 인덱스는 허용 X
- 부동 소수점 값은 해시되기 전에 정수로 변환
- 지리공간적 인덱스
- 지구의 곡률을 포함하여 지리적 거리를 효율적으로 계산할 수 있는 인덱스
8.2.2 인덱스 관리
인덱스 생성과 삭제
생성
// createIndex 호출로 생성 // 헬퍼 메서드도 동일한 적업 시행 use green; spec = {ns: "green.users", key: {'addresses.zip': 1}, name: 'zip'}; // 인덱스 생성 db.system.indexes.insert(spec, true); // 인덱스 확인 db.system.indexes.find().pretty(); { "ns" : "green.users", "key" : { "addresses.zip" : 1 }, "name" : "zip", "v" : 1 }삭제
- system.indexes에 직접 인덱스 도큐먼트 삭제 연산은 금지되어 있음
- deleteIndexes를 수행해서 인덱스 삭제 가능
use green; db.runCommand({deleteIndexes: "users", index: "zip"});
use green;
db.users.dropIndex("zip_1");
```인덱스 구축
- currentOP(): 인덱스 빌드 과정 확인
> db.currentOp() { "inprog" : [ { "opid" : 83695, // 연산ID "active" : true, "secs_running" : 55, "op" : "insert", "ns" : "stocks.system.indexes", // 쿼리상에서 인덱스 사용 확인 "insert" : { // stock 데이터베이스 "v" : 1, "key" : { "desc" : 1 }, "ns" : "stocks.values", "name" : "desc_1" }, "client" : "127.0.0.1:56391", "desc" : "conn12", "threadId" : "0x10f20c000", "connectionId" : 12, "locks" : { // 연산과 관련된 잠금 "^" : "w", "^stocks" : "W" }, "waitingForLock" : false, "msg" : "index: (1/3) external sort Index: (1/3) External Sort Progress: 3999999/4308303 92%", "progress" : { "done" : 3999999, "total" : 4308303 }, "numYields" : 0, "lockStats" : { "timeLockedMicros" : {}, "timeAcquiringMicros" : { "r" : NumberLong(0), "w" : NumberLong(723) } } } ] } - 인덱스가 생성되는 동안에는 데이터베이스에 읽거나 쓰기를 할 수 없음
- Lock에 대한 해결법
- 백그라운드 인덱싱
- 쓰기 잠금은 되지만 데이터베이스에 대한 다른 읽기나 쓰기를 허용하기 위해 잠시 멈춤
- 인덱스 선언 시 backgorund 옵션 추가
db.values.createIndex({open: 1, close: 1}, {background: true});
- 오프라인 인덱싱
- 일반적으로 복제 노드를 오프라인 상태로 변경
- 인덱스를 구축한 다음 마스터 노드로부터 업데이트
- 업데이트 완료 후 이 노드를 프라이머리 노드로 변경
- 다른 세컨더리 노드들도 오프라인 상태로 바꾼 후 각자 인덱스 구축
- 백그라운드 인덱싱
- 단편화 제거(DEFRAGMENTING)
- 대량의 데이터 삭제가 자주 발생한다면 인덱스가 심하게 단편화됨
- 심하게 단편화가 되었을 때 인덱스 재구축 고려해 볼 수 있음
- reIndex 명령어 수행으로 인덱스 재구축
db.values.reIndex(); - 재구축 동안 쓰기 잠금을 하므로 MongoDB를 일시적으로 사용 X
- currentOP(): 인덱스 빌드 과정 확인
출처
- MongoDB in Action 2nd
'dev > DB' 카테고리의 다른 글
| 이력관리 (0) | 2022.03.22 |
|---|---|
| MongoDB - 업데이트, 원자적 연산, 삭제 (0) | 2021.11.11 |
| MongoDB - 집계2 (0) | 2021.11.04 |
| MongoDB - 집계1 (0) | 2021.10.28 |
| MongoDB - Query Selectors(1) (0) | 2021.10.22 |