이번글과 다음글에서는 MongoDB의 인덱스에 대해 살펴보겠습니다.
MongoDB의 인덱스 중 multikey index, geo index, text index 에 대해서는 다음 글에서 다루겠습니다
-1. Mongo DB index 란
-. mongodb의 인덱스는 B-tree 알고리즘으로 되어있으며 하는 역할 및 인덱스 운영방법은 RDBMS의 인덱스와 동일
-. mongodb 의 프라이머리 키는 mysql과는 달리 클러스터링 인덱스가 아니므로 세컨드리 인덱스와 내부 구조가 동일
-. 브랜치 노드일 때 key 값은 인덱스 필드의 값이고 value는 자식노드의 주소
-. leaf node 일 때 인덱스 key 값은 인덱스 필드의 값, value 는 해당 document 저장 주소 , (auto-increment로 증가하는 논리적 record ID)
=> document의 크기가 커져서 데이터 파일 내 위치가 이동되더라도 논리적 주소는 변하지않음
-. 인덱스 리프노드의 value 값이 논리적 주소임에도 실제 데이터파일의 document를 찾을 수 있는 이유는 이 논리 record_id 를 인덱스 키로 가지는 내부 인덱스가 하나 더 있기 때문
-. collection를 생성할 때 자동적으로 record_id 를 키로하는 인덱스가 생성됨
=> wiredTiger storage index에서는 프라이머리 키, 세컨더리 인덱스로 document를 검색할때
리프노드의 논리적 record_id 를 조회하고, record_id 인덱스를 조회하는, 두번의 인덱스 검색 과정을 거치게됨
-2. 인덱스 종류
-. _id index
mongo-repl:PRIMARY> db.mycollection.getIndexes() [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.mycollection" } ] mongo-repl:PRIMARY> db.mycollection.find() { "_id" : ObjectId("5d617c5ff6a0bbc37c6ace8b"), "name" : "sample" } { "_id" : ObjectId("5da32b7950efb81773eef76e"), "name" : "kimdubi" }
=> collection 을 생성할 때 자동으로 생성되는 인덱스로 document의 주소를 갖고있음
-. single field index
mongo-repl:PRIMARY> db.mycollection.createIndex({name:1}) mongo-repl:PRIMARY> db.mycollection.getIndexes() { "v" : 2, "key" : { "name" : 1 }, "name" : "name_1", "ns" : "test.mycollection" }
{name:1} => name ASC, {name:-1} => name DESC
-. compound field index
mongo-repl:PRIMARY> db.mycollection.createIndex({name:1,age:1}) mongo-repl:PRIMARY> db.mycollection.getIndexes() { "v" : 2, "key" : { "name" : 1, "age" : 1 }, "name" : "name_1_age_1", "ns" : "test.mycollection" }
-. hash index
mongo-repl:PRIMARY> db.mycollection.createIndex({name:"hashed"}) mongo-repl:PRIMARY> db.mycollection.createIndex({name:"hashed",age:"hashed"}) { "operationTime" : Timestamp(1570977919, 1), "ok" : 0, "errmsg" : "Currently only single field hashed index supported.", "code" : 16763, "codeName" : "Location16763", "$clusterTime" : { "clusterTime" : Timestamp(1570977919, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
=> range scan에는 사용불가, 단일 건 검색에 최적화되어있음
주로 hash-sharding을 구현하기 위해 사용되는 인덱스
compound index 및 범위조건으로는 인덱스 생성불가
-.3 인덱스 속성
-.unique
mongo-repl:PRIMARY> db.mycollection.find({name:"kimdubi"}) { "_id" : ObjectId("5da32b7950efb81773eef76e"), "name" : "kimdubi" } { "_id" : ObjectId("5da3319f50efb81773eef773"), "name" : "kimdubi" } { "_id" : ObjectId("5da331a150efb81773eef774"), "name" : "kimdubi" } { "_id" : ObjectId("5da331a150efb81773eef775"), "name" : "kimdubi" } { "_id" : ObjectId("5da331a250efb81773eef776"), "name" : "kimdubi" } { "_id" : ObjectId("5da331a250efb81773eef777"), "name" : "kimdubi" } { "_id" : ObjectId("5da331a350efb81773eef778"), "name" : "kimdubi" } { "_id" : ObjectId("5da331a350efb81773eef779"), "name" : "kimdubi" } mongo-repl:PRIMARY> db.mycollection.createIndex({name:1},{unique:true}) { "operationTime" : Timestamp(1570976236, 2), "ok" : 0, "errmsg" : "E11000 duplicate key error collection: test.mycollection index: name_1 dup key: { name: \"kimdubi\" }", "code" : 11000, "codeName" : "DuplicateKey", "keyPattern" : { "name" : 1 }, "keyValue" : { "" : "kimdubi" }, "$clusterTime" : { "clusterTime" : Timestamp(1570976236, 2), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0)}}}
-. partial
mongo-repl:PRIMARY> db.mycollection.createIndex({name:1},{partialFilterExpression:{age:{$gt:1}}}) mongo-repl:PRIMARY> db.mycollection.find({name:"kimdubi1",age:{$gt:2}}).explain() { "parsedQuery" : { "$and" : [ { "name" : { "$eq" : "kimdubi1" }}, { "age" : { "$gt" : 2}}] }, "queryHash" : "CF57D41A", "planCacheKey" : "3B9D692D", "winningPlan" : { "stage" : "FETCH", "filter" : { "age" : { "$gt" : 2 }}, "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "name" : 1 . .
=> 인덱스 필드의 특정 범위에 대해서만 인덱싱 하는 기능
-. TTL
mongo-repl:PRIMARY> db.eventlog.createIndex({date:1},{expireAfterSeconds:60}) mongo-repl:PRIMARY> db.eventlog.find() { "_id" : ObjectId("5da33d5150efb81773eef77d"), "evnt_name" : "kimdubi", "date" : "2019-10-14 12:00:00" } { "_id" : ObjectId("5da33f1850efb81773eef77e"), "evnt_name" : "kimdubi", "date" : "2019-10-14 00:14:00" } { "_id" : ObjectId("5da33f7e50efb81773eef77f"), "evnt_name" : "kimdubi", "date" : ISODate("2019-10-13T15:15:10.100Z") } mongo-repl:PRIMARY> db.eventlog.getIndexes() { "v" : 2, "key" : { "date" : 1 }, "name" : "date_1", "ns" : "test.eventlog", "expireAfterSeconds" : 60 } mongo-repl:PRIMARY> db.eventlog.find() { "_id" : ObjectId("5da33d5150efb81773eef77d"), "evnt_name" : "kimdubi", "date" : "2019-10-14 12:00:00" } { "_id" : ObjectId("5da33f1850efb81773eef77e"), "evnt_name" : "kimdubi", "date" : "2019-10-14 00:14:00" }
=> TTL index는 date type 에 대해서만 동작함