Google AdSense (text)

hidden logo stop

Moving

거지 같은 이글루스 광고노출 정책이 싫어서,
새 보금자리(http://blog.leocat.kr/)로 이사감.

[MongoDB] Object ID에 관해 Computer & Program

MongoDB는 document DB이고, 모든 document마다 고유한 번호(?)가 붙어있다. collection에서 document를 유있하게 찾을 수 있는 죄수 번호 같은.. 이 번호의 이름은 Object ID이다. Object ID는 여러 특징이 있으니 데이터 특성에 따라 잘 만들어 사용해야 한다.


Object ID의 특징

1. 매우 중요한 attribute이고, _id 필드에 저장된다. 일반 collection에서는 항상 indexing된다. Document를 빨리 찾으려면 당연히 indexing되어 있어야 할 것이다. (system에서 사용하는 collection이나 capped collection 등 일부 경우는 indexing되지 않는다.) 모든 document에 추가되기 때문에 collection에 넣기 전에 설정해주지 않으면 BSON ObjectId 타입으로 자동으로 추가된다. (Bson ObjectId 타입은 아래에서 설명한다.)

2. 한 collection에서 중복될 수 없다. Document를 구분할 수 있는 키이기 때문에 중복되면 안 된다. Collection에 넣을 때(insert) _id 필드를 지정해 주지 않으면 자동으로 추가된다. 추가할 때 동일한 _id가 있다면 document는 추가되지 않는다.

3. 한번 입력된 document는 _id를 변경할 수 없다. 변경하려고 시도하면 "Mod on _id not allowed" 에러가 발생한다. getLastError로 확인할 수 있다.

4. _id는 배열을 제외한 어떤 타입이라도 사용할 수 있다. BSON ObjectId라는 특수한 타입이 있으니 이걸 사용해도 된다. 위에서도 설명했지만, collection에 추가 시 _id를 지정하지 않으면 BSON ObjectId 타입으로 추가된다.



BSON ObjectId 데이터 타입

1. 고유한 값을 만들기 위해서 제공하는 특수한 타입이다. 12 byte binary로 구성되며, 각 바이트는 아래와 같이 구성된다.
  + [0..3] : TimeStamp - Unix style timestamp이다. 예전에 이걸로 삽질한 적이 있는데, 이 unix time은 1970년부터 second 단위로 카운팅하지만, Java에서 일반적으로 사용하는 timestamp는 milli second 단위이니 조심해야 한다.
  + [4..6] : Machine - 서버 hostname의 해시값 중 첫 3 byte
  + [7..8] : pid - ObjectId를 생성해 내는 프로세스의 process id
  + [9..11] : Increment - 랜덤한 숫자로부터 시작하면서 하나씩 증가하는 숫자

2. ObjectId() 함수를 사용하면 생성할 수 있다. ObjectId("24자리 16진수 문자열")를 사용하면 되며, 주어진 값을 이용해 12 byte 길이의 바이너리 값이 생성된다. 왜 12 byte인고 하면.. 16진수(= 4bit) x 24자리 = 96 bit = 12 byte 이기 때문이다.
$ mongo
> ObjectId()
ObjectId("507523ea5a8e728ae1a8b94f")

> ObjectId("47cc67093475061e3d95369d")
ObjectId("47cc67093475061e3d95369d")

> ObjectId("47cc67093475061e3d95369")
Wed Oct 10 15:34:48 Assertion: 10448:invalid object id: length
.. 오류 메시지 .. 마지막 1자리가 짧아서 오류 ..

> ObjectId("47cc67093475061e3d95369da")
Wed Oct 10 15:34:49 Assertion: 10448:invalid object id: length
.. 오류 메시지 .. 마지막 1자리가 길어서 오류 ..

> ObjectId("47cc67093475061e3d95369dz")
Wed Oct 10 15:34:50 Assertion: 10448:invalid object id: length
.. 오류 메시지 .. 마지막 1자리가 16진수가 아니라 오류 ..

> db.test.insert({_id:ObjectId("47cc67093475061e3d95369d"), name:'Sigel', site:'http://entireboy.egloos.com/'})

> db.test.insert({_id:ObjectId("47cc67093475061e3d95369d"), name:'Sigel', site:'http://entireboy.egloos.com/'})
E11000 duplicate key error index: test.test.$_id_ dup key: { : ObjectId('47cc67093475061e3d95369d') }

> db.test.insert({name:'Sigel', age:'secret'})

> db.test.find({name:'Sigel'})
{ "_id" : ObjectId("47cc67093475061e3d95369d"), "name" : "Sigel", "site" : "http://entireboy.egloos.com/" }
{ "_id" : ObjectId("507cf9c6f6257531e944b260"), "name" : "Sigel", "age" : "secret" }

3. 고유하고 랜덤한 값을 만들어 내기 위해서는 UUID 등을 사용해도 좋다. BSON ObjectId는 12 byte 길이 이지만, UUID는 128 bit로 16 byte 길이이기 때문에 더 많은 키를 생성할 수 있기 때문이다. 하지만, 어떤 타입이든 사용할 수 있기 때문에 BSON ObjectId이든 UUID이든 크게 상관없다. (개인적인 생각으로는 index 잘 타게 랜덤하게 만들어 낼 수 있으면 좋을듯)
단, 모든 _id 필드는 indexing이 되고, indexing에는 b-tree가 사용되기 때문에 기울어진 사향 트리에 조심해야 한다. (사향 트리는 indexing 되나마나 할 수 있으니..) 때문에 기존 RDBS의 auto incremnt와 같은 PK는 사용하지 않는 것이 좋을 것 같다. (이건 개인적인 생각이다.)


- 참고
http://www.mongodb.org/display/DOCS/Object+IDs
http://www.mongodb.org/display/DOCS/Optimizing+Object+IDs
http://www.mongodb.org/display/DOCS/Indexes

덧글

댓글 입력 영역

Google AdSense (text/image)