안녕하세요. 이번 시간에는 인덱스(Index)에 대해 알아보겠습니다!
인덱스
DB에서 인덱스는 정말 중요한 역할을 합니다. 자주 조회되는 필드를 따로 저장해서 조회 밑 정렬 시의 속도를 빠르게 하는 기법입니다.
예를 들어, 지금까지 사용했던 monsters 컬렉션을 봅시다. 조회할 때 대부분 name 필드로 조회합니다. 이 때 name 필드에 인덱스를 설정해주면 훨씬 빠르게 조회할 수 있습니다.
db.monsters.createIndex({ name: ±1 });
만약 오름차순으로 설정하고 싶다면 1을, 내림차순으로 설정하고 싶다면 -1을 넣어주면 됩니다.
인덱스는 일반 필드 뿐만 아니라, 객체 값을 가지는 필드의 내부 속성에도 지정할 수 있습니다. 예를 들어 { name: { first: 'Zero', last: 'Cho' } }
가 있을 경우, createIndex({ 'name.last': 1 });
이렇게 인덱스 지정이 가능합니다.
참고로 _id 필드는 자동으로 인덱스 설정이 되어 있습니다. 웬만한 경우면 _id를 사용해서 조회하는 게 좋습니다.
복합 인덱스
또한 인덱스는 하나의 필드에만 지정할 필요는 없습니다. 여러 개의 필드를 묶어서 지정할 수도 있습니다. 복합 인덱스라고 불립니다.
db.monsters.createIndex({ name: 1, hp: 1, xp: 1 });
이 경우는 db.monsters.find({ name: 'Slime', hp: 25, xp: 10 });
와 같이 조회할 때 빠르게 찾을 수 있도록 도와줍니다.
복합 인덱스는 순서가 중요합니다. 예를 들어, a, b, c 필드 순서로 인덱스를 설정한 경우, 자동으로 a와 a, b 필드에 대한 인덱스도 같이 생성됩니다. 위의 경우, name 필드만 조회하거나 name, hp 필드를 조회할 때도 뒤의 인덱스를 사용할 수 있습니다. 하지만 hp 필드만 조회하거나 hp, xp 필드를 조회할 때는 인덱스를 사용할 수 없습니다.
특수 인덱스
텍스트 인덱스
인덱스를 지정할 때 ±1 대신 text라고 넣어줍니다. 이 경우 $text 쿼리 연산자를 사용할 수 있습니다.
공간 인덱스
인덱스를 지정할 때 2d나 2dsphere을 넣어줍니다. 이 경우 공간 쿼리 연산자들을 사용할 수 있습니다. 2dsphere는 2d와는 달리 GeoJSON 객체를 지원합니다.
인덱스 특성
조회
인덱스는 처음 db를 만들 때 자동으로 생성되는 system.indexes 컬렉션에 저장됩니다. 안의 내용을 한 번 볼까요?
db.monsters.getIndexes();
일단, 아까 말했듯이 _id에는 자동으로 인덱스가 설정되어 있고요. 복합 인덱스를 설정한 부분도 잘 들어가 있네요.
제거
특정 인덱스를 제거하려면
db.monsters.dropIndex(필드이름);
하면 되고, 모두 제거하려면 다음과 같이 합니다.
db.monsters.dropIndexes();
조합
몽고DB는 똑똑하게 여러 인덱스를 조합합니다. 만약 name필드와 hp필드에 대한 인덱스가 따로 있으면, db.monsters.find({ name: 'Slime', hp: { $gt: 10 } })
를 할 경우, 두 인덱스를 모두 사용하여 조회합니다.
단점
인덱스의 단점은 인덱스 자체가 용량을 차지한다는 겁니다.
db.monsters.totalIndexSize();
위의 인덱스 하나를 설정했더니 16kb나 잡아먹네요. 너무 많은 인덱스를 사용해서 용량을 낭비하지 않도록 합시다. 인덱스는 설계가 중요합니다. 위에 복합 인덱스에서 순서도 영향을 주는 것 보셨죠? 최소한의 인덱스로 효율적인 조회를 할 수 있게 설계해봅시다.
다음 시간에는 몽고DB와 같이 많이 쓰이는 몽구스(Mongoose)에 대해 알아보겠습니다!