인덱스, Index 란?
책의 마지막 쪽에 있는 '인덱스', '찾아보기' 와 비슷하다. 책의 '인덱스'에 적힌 페이지 번호는 해당 데이터의 주소에 비유할 수 있다. DBMS도 사람이 책의 인덱스를 보고 해당 페이지를 찾는 것처럼 데이터를 찾는다. 데이터와 저장된 위치를 키와 값의 쌍 (key-value pair)으로 관리한다.
DB의 검색을 신속하게 하기 위해 데이터의 순서를 미리 정해두는 과정이다. 특정 데이터 필드를 인덱스로 지정하여 검색 결과를 빠르게 얻을 수 있다.
DBMS에서 인덱스는 데이터의 저장성능을 희생해서 상대적으로 데이터의 읽기 속도를 향상시키는 존재 -> 테이블에 인덱스 하나를 더 추가할지 말지는 데이터의 저장 속도를 얼마나 더 희생할 수 있는지, 읽기(조회) 속도를 얼마나 더 빠르게 만들어야 하는지 조율하면서 결정해야한다.
많은 도큐먼트 (전체 컬렉션 도큐먼트의 15~20% 이상)를 읽어야 할 때에는 인덱스를 이용하지 않고 컬렉션 스캔 (풀 테이블 스캔) 으로 필요한 레코드를 가려내는 방식이 더 좋다고 한다.
하나의 쿼리에 하나의 Index가 유효하다. 두 개의 Index가 필요하다면 복합 index를 사용한다.
INDEXES
MongoDB는 쿼리를 수행할 때 스스로 어떻게 처리할지 고민하고 최선의 방법으로 인덱스를 활용한다. 적합하지않은 인덱스가 지정되었을 때 비효율적이라고 판단되면 사용하지 않기도 한다. 좋은 인덱스 전략을 세우는 가장 중요한 요소는 반복적인 테스트이다. 인덱스 검사를 위해 주로 사용하는 매서드는 hint()와 explain()이 있다.
A Single Field Index, 단일 인덱스
쿼리에서 단 하나의 Key만을 이용하면 단일 키 인덱스를 사용해야 한다.
db.[collectionName].createIndex({ isDone: 1 })
// 1은 오름차순, -1은 내림차순을 의미
1 은 오름차순 -1은 내림차순을 의미한다. 일렬로 나열되어 있기 때문에 오름차순이든 내림차순이든 동일한 성능을 낸다. 하나의 쿼리에서 단일 인덱스 두 개를 사용하면 MongoDB가 그 중 제일 효율적인 인덱스를 선택하지만 그 결과가 항상 최선은 아닐 수도 있다.
db.[collectionName].find().sort({ isDone: 1 }) // 오름차순으로 찾는다
db.[collectionName].find().sort({ isDone: -1 }) // 내림차순으로 찾는다 - 같은 일렬로 나열된 데이터라 성능은 동일
위의 두 가지 find().sort() 쿼리의 성능은 동일하다 !
Compound Index (Multiple Fields Index) , 복합 인덱스
검색어에 여러 키가 사용된다면 복합 인덱스로 정의해주어야 한다.
db.[collectionName].createIndex({ userid: 1, score: -1 })
userid와 score 두 개의 복합 인덱스를 설정했다고 해서 각각 다른 쿼리에 각각의 키로 검색 할 수는 없다. userid와 score두 인덱스가 함께 저장되어 있고 userid는 오름차순으로 정렬되어 있지만 score는 그렇지 않다. 하지만 동일한 userid 가 여러개의 score를 가지고 있다면 해당 userid의 내의 score정렬은 내림차순으로 정해진다.
위와 같이 복합 인덱스를 설정했다면 쿼리문을 작성할 때도 순서를 맞춰주어야 효율적인 검색이 가능하다. ( 또는 정 반대의 경우로)
db.[collectionName].createIndex({ userid: 1, score: -1})
db.[collectionName].find().sort({ userid: 1, score: -1 }) // 성능이 좋다
db.[collectionName].find().sore({ userid: -1, score: 1 }) // 성능이 좋다
db.[collectionName].find().sore({ score: -1, userid: 1 }) // 성능이 안좋다
db.[collectionName].find().sore({ userid: -1, score: 1 }) // 성능이 안좋다
단일 인덱스의 경우 일렬로 나열된 데이터 구조 덕에 내림차순이든 오름차순이든 성능에 차이가 없었다. 마찬가지로 컴파운드 인덱스를 구성하는 키들의 방향이 서로 다르더라도 데이터 구조는 일렬로 나열되어 있기 때문에 각 키의 방향 조합만 맞춰주면 동일한 효과를 가져온다.
Index Prefix, 인덱스 프리픽스
정의된 복합 인덱스의 앞 쪽부터 포함되는 부분집합의 인덱스를 Prefix라고 말한다. (꼭 앞에서부터 순차적이어야 한다.) 즉, 복합 인덱스를 먼저 선언 후에 프리픽스를 사용할 수 있다. 아래 예시를 보면
db.[collectionName].createIndex( {a:1, b:1, c:1, d:1 } ) // 복합 인덱스 설정
// 위의 복합인덱스에서 사용할 수 있는 프리픽스들
{ a:1 }
{ a: 1, b: 1 }
{ a: 1, b: 1, c: 1 }
{ a: 1, b: 1, c: 1, d: 1 }
db.collectionName.find().sort({a : 1}) // index prefix { a: 1 }
db.collectionName.find().sort({a : -1}) // index prefix { a: 1 }
db.collectionName.find().sort({a : 1, b : 1}) // index prefix { a: 1, b: 1 }
db.collectionName.find().sort({a : -1, b : -1}) // index prefix { a: 1, b: 1 }
db.collectionName.find().sort({a : 1, b : 1, c : 1}) // index prefix { a: 1, b: 1, c: 1 }
db.collectionName.find({a: { $gt: 4 } }).sort( { a: 1, b: 1 } ). // index prefix { a: 1, b: 1 }
예를 들어, "a" field없이 "b" field 조회하는 (순차적으로 있지않은) 쿼리들
Index Intersection
인덱스 교차란 인덱스가 교차해서 쿼리에 자동 적용되는 것을 말한다. 예를 들면,
db.collectionName.createIndex({ qty: 1 })
db.collectionName.createIndex({ item: 1 })
-> db.collectionName.find( { item: 'abc', qty: { $gt: 15 } } ) // 인덱스가 적용된다.
위의 쿼리에 .explain()을 사용해보면 AND_SORTED or AND_HASH가 나온다.
DB 처리 성능을 최적화하기 위해 index의 이해는 매우 중요하다고 한다! 가장 좋은 쿼리를 만들기 위한 고민과 노력을 계속 하기!
References: https://docs.mongodb.com/manual/tutorial/sort-results-with-indexes/
'mongoDB' 카테고리의 다른 글
[MongoDB] Mongoose Query 총 정리 (0) | 2021.11.15 |
---|---|
[MongoDB] options - lean, new, upsert (0) | 2021.11.15 |
[MongoDB] DAS, NAS, SAN, HDD, SSD, 인덱스란? (0) | 2021.11.11 |
[MongoDB] Node.js express CRUD with mongoDB (2) | 2021.09.28 |
[MongoDB] 몽고디비란? 기본 개념, 장점 단점 / CRUD (2) | 2021.09.23 |