배달 어플 서비스 데이터를 몽고에 저장한다고 가정하고 스키마를 작성해보자
<aside> 1️⃣ 식당 컬렉션에 리뷰 데이터를 배열 필드로 저장
// DB 생성
> use delivery
// 첫번째 식당 데이터 삽입
> db.shops.insertOne({
... _id: 1,
... name: "Tommy Steak House",
... desc: "Greatest Steak House Ever.",
... phone: "000-1234-1234",
... reviews: [
... {
... review_id: 1,
... user: "James",
... review: "So Good!!",
... date: new Date(),
... rating: 10
... },
... {
... review_id: 2,
... user: "Tommy",
... review: "Not Bad.",
... date: new Date(),
... rating: 7
... },
... {
... review_id: 3,
... user: "Kevin",
... review: "냠냠긋!!",
... date: new Date(),
... rating: 5
... },
... ]
... })
// 랜덤으로 두번째 식당의 리뷰 데이터를 생성할 함수 구현
> const generateRandomString = (num) => {
... const characters ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
... let result = '';
... const charactersLength = characters.length;
... for (let i = 0; i < num; i++) {
... result += characters.charAt(Math.floor(Math.random() * charactersLength));
... }
...
... return result;
... }
> generateRandomString(50)
bmJcVSOWWNWRjGDIdYusORSonbXIauYnQleGkPVNrOYUnJXdmT
// 두번째 식당 데이터 삽입
> db.shops.insertOne({
... _id: 2,
... name: "Kevin's Pizza",
... desc: "Italian Style Pizza",
... phone: "000-0000-1111",
... reviews: []
... })
> for (i = 0; i < 800; i++){
... review = {
... review_id: i,
... user: generateRandomString(5),
... review: generateRandomString(10),
... date: new Date(),
... rating: Math.floor(Math.random() * 10)
... }
... db.shops.updateOne(
... {
... _id: 2
... },
... {
... $push: {
... reviews: review
... }
... }
... )
... }
// 저장한 식당 정보 확인
> db.shops.findOne({ _id: 2 })
{
_id: 2,
name: "Kevin's Pizza",
desc: 'Italian Style Pizza',
phone: '000-0000-1111',
reviews: [
{
review_id: 0,
user: 'nXvqK',
review: 'zpTESxycLu',
date: ISODate("2023-05-16T16:21:48.924Z"),
rating: 4
},
{
review_id: 1,
user: 'NJAOQ',
review: 'HkxZaaHWGC',
date: ISODate("2023-05-16T16:21:48.950Z"),
rating: 2
},
{
review_id: 2,
user: 'mvFRI',
review: 'BIllMpFCMW',
date: ISODate("2023-05-16T16:21:48.978Z"),
rating: 2
},
...
// 리뷰 800개
...
]
}
// 각 식당 도큐먼트 사이즈 계산
> Object.bsonsize(db.shops.findOne({ _id: 2 }))
71997
> Object.bsonsize(db.shops.findOne({ _id: 1 }))
380
문제점!!
고객은 여러 음식점을 클릭해서 보게 됨 → 음식점 클릭 시 해당 음식점의 정보를 조회하기 전, 내부적으로 캐시에 있는지 확인 → 캐시에 없으면 캐시에 올린 다음 document를 읽음 → Working Set이 shop collection 전체가 되어버림 → 캐시 사이즈가 shop collection보다 작으니, 중간중간 cache eviction 발생 → 이 때 사용자는 서비스의 속도가 크게 저하되는 것을 느낌
✔️ 캐시 사용량이 뚝 떨어지는 구간 = cache flush가 발생하는 구간 ✔️ 계단식으로 올라가는 구간 = disc로부터 데이터를 읽어 캐시에 적재하는 구간
여러 사용자가 몰리게 되면 캐시 사용량이 늘어나지 못하고, 데이터를 읽어오느라 속도가 저하됨
</aside>
<aside> 2️⃣ Subset Pattern을 사용한 모델링
Working Set을 줄이는 방법 👉 사용자의 패턴을 분석해 Document의 각 사이즈를 줄여준다
다 읽어올 필요가 없는 필드는 따로 컬렉션으로 빼서 저장 → 도큐먼트 크기를 줄임
<aside> ✅ Subset Pattern
도큐먼트의 일부를 다른 컬렉션에 한번 더 저장하도록 스키마를 디자인하는 것
</aside>
// 기존 컬렉션 삭제
> db.shops.find()
> db.shops.drop()
// shops 컬렉션에 식당 데이터 삽입
> db.shops.insertOne({
... _id: 2,
... name: "Kevin's Pizza",
... desc: "Italian Style Pizza",
... phone: "000-0000-1111",
... reviews: []
... })
// reviews 컬렉션에 리뷰 데이터 삽입
> for (i = 0; i < 800; i++){
... review = {
... review_id: i,
... user: generateRandomString(5),
... review: generateRandomString(10),
... date: new Date(),
... rating: Math.floor(Math.random() * 10)
... }
... db.reviews.insertOne(review)
... db.shops.updateOne(
... {
... _id: 2
... },
... {
... $push: {
... reviews: review
... }
... }
... )
... }
// 저장된 리뷰 데이터 확인
> db.reviews.find()
[
{
_id: ObjectId("6463b095744ecd33df4213c0"),
review_id: 0,
user: 'BjwFz',
review: 'ZtcOdYFNFm',
date: ISODate("2023-05-16T16:34:29.111Z"),
rating: 9
},
{
_id: ObjectId("6463b095744ecd33df4213c1"),
review_id: 1,
user: 'aHcLp',
review: 'xEtMmSFEjM',
date: ISODate("2023-05-16T16:34:29.181Z"),
rating: 5
},
{
_id: ObjectId("6463b095744ecd33df4213c2"),
review_id: 2,
user: 'onsRO',
review: 'CPdtwfYTbJ',
date: ISODate("2023-05-16T16:34:29.223Z"),
rating: 8
},
...
]
// 식당에는 10개의 리뷰 데이터만 저장
db.shops.updateOne(
... {
... _id: 2
... },
... {
... $push: {
... reviews: {
... $each: [review],
... $slice: -10
... }
... }
... }
... )
// 업데이트된 식당 데이터 확인
> db.shops.find()
[
{
_id: 2,
name: "Kevin's Pizza",
desc: 'Italian Style Pizza',
phone: '000-0000-1111',
reviews: [
{
review_id: 791,
user: 'UuXJH',
review: 'byPvsCZJIT',
date: ISODate("2023-05-16T16:35:00.871Z"),
rating: 4
},
{
review_id: 792,
user: 'sogOw',
review: 'MaokoKihND',
date: ISODate("2023-05-16T16:35:00.910Z"),
rating: 5
},
// 이하 8개 리뷰 데이터
...
]
}
]
</aside>