[MongoDB] 인덱스 생성 및 인덱싱 전략

robert·2022년 9월 12일
0
post-custom-banner

Single Field Index(단일 필드 인덱스)?

  • 하나의 필드를 인덱스로 사용하는 것을 단일 필드 인덱스라고 한다. 필드 옆에 숫자는 정렬 방식을 의미한다. 1은 오름차순 -1은 내림차순. 하지만 단일 필드 인덱스에서는 오름차순이나 내림차순은 의미가 없다고 한다.
    ex) db.getCollection("koreanpremium.history").createIndex({ "unitDatetime": -1 })
    Compound Index?
  • 2개 이상의 field를 사용하는 Index를 복합인덱스라고 한다.

사용방법?

  • db.collection.createIndex({ field1: type, field2: type2, ... })
  • field에는 인덱스로 잡을 collection의 field명, type에는 1 혹은 -1 정렬방식을 넣는다.
  • unique: true 속성을 추가하면 Index를 unique key로 만들 수 있다.
    ex) db.collection.createIndex( { field1: type, field2: type2, ... }, { unique: true })
  • aboutbit 사용 예시 : db.getCollection("koreanpremium.history").createIndex({ "unitDatetime": -1, "globalSymbol": 1}, { unique: true })

Indexing 전략

  1. Sort 시 인덱스 순서를 고려해야 한다.
  • 키로 잡은 field의 순서와 조회 시 순서가 동일해야 인덱스를 타고 조회한다. 그러므로 인덱스를 잡을 경우 키의 순서를 잡을때 신경써야 한다. 예를 들어 unitDatetime-globalSymbol 순서의 정렬은 지원하지만 globalSymbol-unitDatetime 정렬은 지원하지 않는다.
  1. 정렬 방향을 고려해야 한다.
  • index를 사용한 정렬을 이용하기 위해서는 생성된 인덱스의 정렬 방향과 같거나 역으로 조회하는 쿼리만 인덱스를 탄다.
  • index 타는 쿼리 : sort({ "unitDatetime": -1, "globalSymbol": 1 }) 혹은 sort({ "unitDatetime": 1, "globalSymbol": -1 })
  • index 타지 않는 쿼리 : sort({ "unitDatetime": 1, "globalSymbol": 1 }) 혹은 sort({ "unitDatetime": -1, "globalSymbol": -1 })
  1. Prefixes
  • 복합 인덱스의 가장왼쪽 필드를 시작으로 만들어진 인덱스의 부분집한 인덱스를 말한다.
  • 예를 들어보면, { unitDatetime:1, buyVolUsd:1, sellVolUsd:1 }로 이루어진 Compound Index는 { unitDatetime:1 }, { unitDatetime:1, buyVolUsd:1} 앞의 2개의 Index Prefixes를 가지고 있다.
  • 이 Index Prefixes는 인덱스처럼 동작을 한다. sort({ unitDatetime: 1 }), sort.({ unitDatetime: 1, buyVolUsd:1 })로 정렬 조회를 하면 위의 인덱스 Prefixes를 통해 조회가 된다.
  1. non-prefix 조회
  • 정렬 조회 시에 prefix가 아닌 경우도 조회가 가능하다. 단, Equality 상태인 경우에만 가능하다.
  • db.collection.find({ unitDatetime: ISODate("2022-06-25T14:45:00.000+0000") }).sort({ buyVolUsd:1, sellVolUsd:1 }) 선행인 unitDatetime이 정렬조건에 없지만 Equality 상태이므로 인덱스를 사용한 조회가 가능하다.

추가로 기존 데이터가 중복일 경우 중복을 제거하는 방법이다.
아래 코드를 몽고 쉘에서 작성하여 실행함으로써 중복 데이터 제거 가능하다.

var duplicates = [];

db.getCollection("traderposition.total")
.aggregate(
    [
        { $group: {
            // _id는 group으로 묶을 field 세팅
            _id: { unitDatetime:"$unitDatetime", symbol:"$symbol" },
            // 아래의 field는 grouping의 결과로 보여줄 field
            dups: { "$addToSet": "$_id" },
            count: { "$sum": 1 }
            }
        },
        { $match: {
            count: { "$gt": 1 }
            }
        }
    ]
) // You can display result until this and check duplicates
.forEach(function(doc) {
    doc.dups.shift(); // First element skipped for deleting
    doc.dups.forEach(function(dupId) {
            duplicates.push(dupId); // Getting all duplicate ids
        })
    }
)

// 삭제 대상 출력
printjson(duplicates);

// 대상을 가지고 실제 삭제 
db.getCollection("traderposition.total").remove({_id:{$in:duplicates}}) // $in -> rdbms의 in 과 비슷한 역할
profile
화이팅!
post-custom-banner

0개의 댓글