[mongodb] Indexing
index 사용으로 query의 속도를 향상시킨다.
(index에 있는 entry로 찾을때는, 그 결과로 바로 jump할 수 있기 때문)
참고로, "username"으로 query한다면, "user_num" field를 indexing할 필요 없다.
왜냐하면, "user_num"으로 query할 일은 없으니깐.
* indexing 소개
아래와 같이 single key로 검색한다고 가정한다.
db.a.find({"field":"value"})
해당 key가 index되면 좀더 속도가 향상된다.
index를 생성하기 위해서, 아래를 실행한다.
db.a.ensureIndex({"field":1})
위 실행은 아래의 속도를 향상시키지는 않는다.
db.a.find({"b":"value"}).sort({"b":1,"a":1})
위 경우 "look through the whole book" 즉, 전체를 검사한다.
이것을 table scan이라고 한다. (즉, index없이 검사함)
다음과 같이 선언가능하다.
db.a.ensureIndex({"a":1, "b":1})
ensureIndex로 전달된 document는 sort로 전달된것과 동일한 형태이여야 한다.
ensureIndex로 전달된 1, -1은 index가 진행될 방향을 의미한다. (sort 정렬을 의미하는 듯함)
single key로 지정된 경우, 방향은 상관이 없다.
single key는 보통 일반책의 index(즉, 알파벳 순)의 구조와 동일하다.
A-Z, Z-A이든 상관없이 M 부터 찾기 시작한다.
하나의 key 이상이라면, index 방향을 고려해야 한다.
다음과 같은 값이라 고려하자.
------------------
| a | b | c |
------------------
| f | 9 | 0 |
| f | 6 | 1 |
| c | 7 | 2 |
| c | 4 | 3 |
| b | 7 | 4 |
| c | 2 | 5 |
| e | 1 | 6 |
| b | 5 | 7 |
| a | 3 | 8 |
| d | 10 | 9 |
| e | 11 | 10 |
------------------
만일, {"a":1, "b":-1}이라면, 다음과 같이 구조화한다.
------------------
| a | b | c |
------------------
| a | 3 | 8 |
| b | 7 | 4 |
| b | 5 | 7 |
| c | 7 | 2 |
| c | 4 | 3 |
| c | 2 | 5 |
| d | 10 | 9 |
| e | 11 | 10 |
| e | 1 | 6 |
| f | 9 | 0 |
| f | 6 | 1 |
------------------
이련 경우 {"a":1, "b":-1} sorting에 적합하지만,
{"a":1, "b":1}은 그다지 효과적이지 못하다. 그때는,
{"a":1, "b":1} index를 그냥 만들면 된다.
일반적으로,
N key를 가지는 index는 어떤 조합으로 이뤄지는 query든 결과를 빠르게 한다.
예를 들어, {"a":1, "b":1, "c":1, ..., "z":1}의 index는
{"a":1}, {"a":1, "b":1}, {"a":1, "b":1, "c":1},...의 query를 빠르게 한다.
{"b":1}, {"a":1, "c":1}과 같은 경우는 최적화되진 않는다.
index 생성의 단점은, 모든 insert, update, remove에서 약간의 overhead 추가이다.
collection당 64개의 index를 추가할 수 있다.
가끔은 index를 쓰지 않아야 효과적인 경우가 있다.
일반적으로 collection의 절반 혹은 그 이상이 return되는 경우,
table scan이 더 효과적일 수 있다.
또, key가 존재하는지, 혹은 boolean 값이 true인지 false인지를 query하는 경우는
index를 쓰지 않는 것이 좋다.
; 규모의 index (scaling indexes)
최근 date 별로 user를 query해야 하는 경우를 살펴보자.
db.status.ensureIndex({user:1, date:-1}) - (1)
인 경우와
db.status.ensureIndex({date:-1, user:1}) - (2)
의 차이점을 잘 이해해야 한다.
(1)의 경우는,
AAA | 2011/12/31
AAA | 2011/06/06
AAA | 2011/01/01
AAB | 2011/05/05
AAB | 2011/03/03
AAC | 2011/04/04
AAC | 2011/02/02
...
ZZZ | 2011/08/08
형태가 되고,
만일 user의 수가 굉장히 많은 규모를 가지는 경우,
부하가 걸린다.
즉, AAA ~ ZZZ까지 모두 뒤져 봐야 하기 때문이다.
(2)의 경우는,
2011/12/31 | AAA
2011/06/06 | AAA
2011/05/05 | AAB
2011/04/04 | AAC
2011/03/03 | AAB
..
와 같은 형태가 되고,
user의 수가 많더라도, 전체가 아닌 부분만 query하는 것이 가능하다.
index를 만들때 다음을 고려해 봐라.
1) 무었을 query하는가? 해당 key는 index가 될 필요가 있다.
2) 각각의 key의 바른 방향은 무었인가?
3) 규모가 클 때는 어떻게 될 것인가? 다른 방향을 한번 생각해 봐라.
; embeded document를 indexing 하기
db.a.ensureIndex({"a.b":1})
와 같이 선언 가능
; sort를 위한 index
collection이 커지면서, sort를 위한 index를 생성하게된다.
만일, index되지 않은 키로 sort한다면, 모든 data를 memory에 올려 sort할 것이다.
즉 테라바이트크기는 sort하지 못한다. index를 만들면 해결된다.
; index의 unique 확인하기
collection안의 각각의 index는 index의 unique가 확인되는 string이 있고,
server에 의해 삭제 혹은 관리된다. index name은, 기본값으로,
keyname1_dir1_keyname2_dir2_...keynameN_dirN와 같이 구성된다.
이러한 index name은 길이의 제한(127 byte)이 있기 때문에,
복잡한 index는 생성 실패될 수 있다. getLastError로 확인할 수 있다.
* unique index
unique index는 주어진 key에 대해 해당 collection의 모든 document가 unique값을
가지도록 보장한다.
db.a.ensureIndex({"a":1},{"unique":true})
db.a.insert({"a":1})
db.a.insert({"a":1})
E11000 duplicate key error index: qqqwww.a.$a_1 dup key: { : 1.0 }
와 같이 동일 값에 대해서 insert가 실패된다.
; 중복 제거하기
이미 존재한 document들에 대해, unique index를 생성하면,
중복값이 포함되어 있을 수 있다.
해당 case를 위해 drop 할 수 있다. (처음만 남기고 이후는 삭제)
{"a":1, "b":1}
{"a":1, "b":2}
가 있을 때,
db.a.ensureIndex({"a":1, {"unique":true})
E11000 duplicate key error index: asdsad.a.$a_1 dup key: { : 1.0 }
db.a.find()
{"a":1, "b":1}
{"a":1, "b":2}
db.a.ensureIndex({"a":1}, {"unique":true, "dropDups":true})
E11000 duplicate key error index: asdsad.a.$a_1 dup key: { : 1.0 }
db.a.find()
{"a":1, "b":1}
; unique index 결합하기
결합된 unique index도 가능하다.
* explain, hint 사용하기
explain은 query에 대한 주요 정보를 알려준다. cursor를 통해 실행한다.
document를 리턴하는데, cursor 그 자체는 아니다.
db.a.find().explain()
{
"cursor" : "BasicCursor",
"nscanned" : 5,
"nscannedObjects" : 5,
"n" : 5,
"millis" : 17,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
db.a.find({"a":1}).sort({"a":-1}).explain()
{
"cursor" : "BasicCursor",
"nscanned" : 5,
"nscannedObjects" : 5,
"n" : 2,
"scanAndOrder" : true,
"millis" : 30,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
db.a.ensureIndex({"a":1})
db.a.find({"a":1}).sort({"a":-1}).explain()
{
"cursor" : "BtreeCursor a_1 reverse",
"nscanned" : 2,
"nscannedObjects" : 2,
"n" : 2,
"millis" : 16,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
"a" : [
[
1,
1
]
]
}
}
db.a.find({"a":1}).sort({"a":1}).explain()
{
"cursor" : "BtreeCursor a_1",
"nscanned" : 2,
"nscannedObjects" : 2,
"n" : 2,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
"a" : [
[
1,
1
]
]
}
}
주요 정보든 다음과 같다.
"cursor" : "BasicCursor"
; index를 사용하지 않았다는 뜻.
"nscanned" : 2
; document를 뒤져본 개수. 이것과 query 개수를 비교해 볼 만 하다.
"n" : 2
; query 개수
"millis" : 0
; query 시간
"cursor" : "BtreeCursor a_1"
; B-tree 구조의 index를 사용함. a_1 index name이 적용됨.
이는 db.system.indexes.find({"ns":"db이름.collection이름", "name":"a_1"})
으로 조회 가능하다.
hint()
; query에 사용될 index를 강제로 지정할 수 있다.
db.a.find({"a":3, "b":4}).hint(("b":1, "a":1})
* index 관리하기
index의 meta 정보는 system.indexes collection에 저장된다.
예약된 collection이므로 임의로 insert/remove 못한다.
ensureIndex 혹은 dropIndex 명령을 통해서 접근된다.
; index 변경하기
db.a.ensureIndex({"a":1}, {"background":true})
를 통해 새로운 index를 db를 운영하는 중간에 생성할 수 있다.
index 생성은 시간을 잡는 작업이다. 위와 같이 하면, background로 작업되며,
요청되는 request들도 처리된다. 만일 해당 option이 없다면, db는 block된다.
물론 block되면 작업은 빨리 끝난다.
dropIndexes로 index를 삭제할 수 있다.
가끔 system.indexes를 통해 index name으로 확인해 봐야 한다.
db.a.dropIndexes()
; 모든 index 삭제
db.a.dropIndex({"a":1, "b":-1})
; index 삭제
db.runCommand({"dropIndexes":"foo", "index":{"a":1}})
; foo collection에서 {"a":1} index 삭제
db.runCommand({"dropIndexes":"foo", "index":"*"})
; foo collection에서 모든 index 삭제
'Research > mongodb' 카테고리의 다른 글
[mongodb] Advanced topics (0) | 2011.09.23 |
---|---|
[mongodb] Aggregation (MapReduce) (0) | 2011.09.22 |
[mongodb] Querying (0) | 2011.09.19 |
[mongodb] Creating, Updating, and Deleting Documents (0) | 2011.09.15 |
mongodb, the definitive guide (o'relly, kristina chodorow, michael dirolf) (0) | 2011.09.15 |