아주 간단한 $lookup
파이프 테스트이다.
실험 환경은 다음과 같다.
users
와 posts
, 2개의 콜렉션이 다음과 같이 존재한다.type User struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Name string `bson:"name"`
}
type Post struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Content string `bson:"content"`
CreatorID string `bson:"creatorID"`
CreatorObjID primitive.ObjectID `bson:"creatorObjID"`
}
posts
의 creatorID
는 users
의 _id
의 헥스 문자열, creatorObjID
는 _id
를 의미한다.여기서 우리는 posts
콜렉션에서 creatorID
또는 creatorObjID
를 통해 users
콜렉션을 lookup
하는 함수에 대하여 벤치마크 측정을 해볼 것이다.
이때, 다음 3개의 함수에 대해서 벤치마크 측정을 실시한다:
1. lookup
없이 그냥 posts
를 읽어들임
2. creatorID
를 objectId
타입으로 변환 후 lookup
실시
3. creatorObjID
를 이용하여 바로 lookup
실시
첫번째 실험에서는 첫 10개의 posts
를 스킵(skip
)하고, 10개를 가져온다(limit
).(2번, 3번 함수는 이 부분을 aggregation 으로 구성하여 우선 skip
파이프와 limit
파이프를 위치시킨다)
첫번째 실험 결과,
1. 대략 700,000 ns/op (ns: nanosecond, op: operation)
2. 대략 1,000,000 ns/op
3. 대략 980,000 ns/op
lookup
은 성능을 대략 42% 정도 더 느리게 만들었다. ObjectId 를 변환하는 파이프는 생각보다 성능 손실이 크지 않음을 알 수 있었다.
두번째 실험으로, 100개의 posts
를 읽어오도록 해보았다. lookup
은 가져오는 개수가 많을수록 크게 느려지는것으로 알려져있다.
두번째 실험 결과,
1. 대략 1,000,000 ns/op
2. 대략 3,500,000 ns/op
3. 대략 3,250,000 ns/op
숫자가 늘어나자 무려 350% 정도 더 느려지는 모습을 볼 수 있다.
Stackoverflow 를 보다보면, lookup
명령어로 인해 크게 성능저하를 겪는 질문글들을 볼 수 있다. 답변을 보면, MongoDB의 Aggregation 파이프라인을 구성할 때, lookup
전에 match
, skip
, limit
등을 통해 최대한 lookup
할 대상 아이템 숫자를 줄여놓는 것을 추천한다. 위의 간략한 실험 결과도 그 추천이 올바름을 보여준다.
index 설정은 하시고, lookup 하신건가요?