인턴생활 하면서 특별한(?) 경험을 했습니다.
RDB와 별 차이 없게 디자인 된 MongoDB를 사용해보게 되었습니다.
이로 인해서 MongoDB가 제공하는 이점을 잘 활용할 수 없었다고 생각합니다.. 🫠
사용해보면서 느낀 점을 정리한 글입니다.
합류 당시 팀에서는 Excel에서 AI 학습 데이터에 대한 레이블을 만들고, 이를 MongoDB에 적재하고 있었습니다.
근데,
Excel의 Column 구조를 그대로 MongoDB의 문서 스키마로 가져와서 사용하고 있었습니다.
즉, 하나의 Document에 모든 메타데이터를 저장했고, Key와 Value가 1대1로 매칭되는 필드의 개수는 매우 많았습니다.
그 결과, MongoDB를 RDB처럼 사용하게 되었습니다..
이렇게 설계된 Collection 기반으로 개발된 것들이 많아서 제가 스키마를 변경하거나 Postgres 같은 RDBMS로 DB를 변경하기엔 힘든 시점이였습니다..🫠
AI 학습 데이터에 대한 메타데이터(레이블)을 저장해야 함
특정 데이터는 모든 레이블이 필요하지 않음
고정된 스키마를 사용하는 RDB보다는 유연한 스키마를 사용하는 NoSQL이 적합하다고 생각
이러한 이유들로 MongoDB를 사용하는 건 합리적이라고 생각했습니다. 하지만..
NoSQL과 SQL의 차이점
NoSQL과 SQL의 가장 큰 차이점은 "스키마" 입니다.
SQL은 "고정된 스키마"를 가지며, 모든 Record는 동일한 열을 가져야 합니다.
반면에, MongoDB는 "유연한 스키마"를 가지며, 각 Document는 다른 구조를 가질 수 있습니다.
고정된 스키마 구조를 사용하면서 생기는 문제가 있었습니다.
만약 Collection A는 동물 정보와 식물 정보를 담은 Document들을 보관하는 저장소라고 합시다.
하지만, 특정 필드는 특정 유형의 Document에만 관련이 있기 때문에
모든 Document가 모든 필드를 가질 필요는 없습니다.
예를 들어, 동물 관련 Document에는 동물 관련 필드가 필요하고, 식물 관련 Document에는 식물 관련 필드가 필요하겠죠. 따라서, 동물 관련 Document가 식물 관련 필드를 가지고 있을 필요는 없습니다.
그런데..
기존 문제의 Collection에는 모든 Document가 모든 필드를 가지고 있었습니다,,
이는 불필요한 공간 낭비를 초래하며, Document의 가독성을 떨어뜨립니다.
따라서, 각 Document는 자신의 특징에 맞는 필드만을 가지는 것이 바람직합니다.
이런 경우에는 필드를 제거하고
true
인 경우에만 필드를 추가하는 방법을 고려해볼 수 있습니다.
극단적인 예로, Value가 있는 필드는 1개, 나머지 필드들은 모두 null로 채워진 것입니다.
null로 채워진 필드들은 그냥 Document에 없어도 되는데 말이죠.
이 경우에는 아예 필드를 제거하는 방법을 고려해볼 수 있습니다.
이 경우에는 배열 필드에 비슷한 성질을 갖는 필드들을 통합하는 방법을 고려해볼 수 있습니다.
이 문제로 인해서 쿼리 작성이 매우 번거로워졌습니다.
A={
"james":{
"age":3,
"country":"USA"
},
"kim":{
"age":4,
"country":"korea"
}
}
B={
"human":[
{
"james":{
"age":3,
"country":"USA"
}
},
{
"kim":{
"age":4,
"country":"korea"
}
}
]
}
A,B 같은 Document 구조가 있다고 해봅시다. A,B 모두 사람에 대한 정보를 담고 있습니다.
B가 더 직관적으로 스키마가 구성되지 않았나요?
여기서 만약에 사람 100명을 추가하면 어떻게 될까요?
A는 새로운 사람 필드를 직접 추가해야 하므로 구조적으로 확장이 번거롭습니다.
반면, B 구조는 "human" 필드의 배열에 새로운 Subdocument로 100개 추가하면 됩니다.
만약 이 상황에서 사람들의 평균 나이를 구하는 쿼리를 작성하려면 어떤 구조가 더 편할까요?
저는 B가 더 편하다고 생각합니다.
A는 어떤 필드가 "human"에 해당하는지 전부 알아야 합니다.
다시 말하면, 쿼리에 human에 해당하는 모든 필드를 명시해줘야 합니다..
반면, B는 "human" 필드에 배열로 저장된 모든 Document에 대해서 연산을 적용하면 됩니다.
따라서 "human"에 해당하는 필드를 찾을 필요가 없는 것이죠.
이런 경우 MongoDB의 Aggregation Pipeline을 이용하여 평균 나이를 쉽게 구할 수 있습니다.
기존의 Collection의 Document들은 A 방식으로 스키마가 구성되어서, 특정 쿼리는 최대 7천 줄 이상 작성해야 하는 불편함이 있었습니다. 물론 사용 목적에 따라, 바깥으로 전부 빼는 A 방식이 효과적일 때도 있습니다.
참고글
https://www.mongodb.com/developer/products/mongodb/mongodb-schema-design-best-practices/