이번글과 다음글에서는 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 에 대해서만 동작함