우리 대부분은 잠자는 동안 관계형 데이터베이스 모델에 대한 첫 번째 찌르기를 할 수 있습니다.
하지만 문서 데이터베이스로 작업하기로 선택했다면 조금 다르게 생각해야 합니다.
더 이상 어렵지 않습니다. 단지 다양한 용도에 맞게 최적화하고 있을 뿐입니다.
그렇다면 이를 제대로 수행하기 위한 기본 사항은 무엇일까요?
생각의 방향을 잡는 데 도움이 되는 세 가지 원칙이 있습니다:
- 궁금해할 만한 질문에 답하세요.
- 편의를 위해 데이터를 삽입하고 무결성을 위해 참조하세요.
- 예측 가능하고 의미 있는 키 이름을 지정하세요.
오늘은 그 중 첫 번째에 대해 자세히 살펴보겠습니다.
답이 아닌 질문
데이터를 관계형 모델의 테이블, 열, 행으로 분할하면 쿼리 가능성을 최적화할 수 있습니다. 거의 제한이 없는 답변의 소스를 구축하고 어떤 질문을 할 것인지에 대한 결정을 미루고 있습니다.
간단한 예를 들자면, Couchbase 브랜드 굿즈를 추적할 수 있는 재고 관리 시스템입니다.
이 시스템에는 티셔츠, USB 스틱, 펜 등이 있습니다. 때때로 모임 그룹, 컨퍼런스, 개인에게 보내달라는 주문을 받기도 합니다.
대부분의 경우 다음과 같은 관계형 테이블이 생성됩니다:
- 제품
- 고객
- 주문
- 주문_세부 정보
한눈에 보기, 주문 세부 정보 는 명확하지 않게 보일 수 있습니다. 하지만 이 방식을 사용하면 첫 번째 일반 형식을 깨지 않고 각 순서의 모든 항목에 대한 참조를 저장할 수 있습니다. 그렇지 않으면 각 주문의 항목을 문자열로 직렬화하여 TEXT 열에 저장해야 합니다.
실수하지 않는 한 각 제품, 고객, 주문은 데이터베이스에 한 번만 표시됩니다. 따라서 기록에 대한 업데이트가 보편적으로 이루어지고 원하는 방식으로 데이터를 매우 쉽게 쿼리할 수 있습니다.
장단점, 항상 장단점은 존재합니다.
이렇게 하면 스웨그 관리 시스템의 데이터를 가장 순수한 형태로 저장한 다음 나중에 원하는 방식으로 쿼리할 수 있습니다.
그렇다면 무엇이 문제일까요?
몇 가지 단점이 있습니다:
- 각 조인마다 디스크 탐색이 필요하고 CPU 오버헤드가 발생하며 페이지가 렌더링되기를 기다리는 사용자가 있기 때문에 SQL 쿼리는 비용이 많이 듭니다.
- 관계형 데이터베이스는 클러스터 전체에서 확장하기가 어렵습니다.
불친절하게 표현하자면, 관계형 데이터 모델링은 미래의 자신으로부터 CPU 사이클을 훔치는 작업이라고 할 수 있습니다.
우리는 대부분의 쿼리 패턴을 초기에 알고 있지만, 데이터에서 해당 컨텍스트를 조심스럽게 제거하는 데 많은 시간을 소비합니다. 데이터를 한 번 분할한 다음 애플리케이션의 나머지 수명 기간 동안 데이터베이스 서버에 데이터를 다시 조합해 달라고 요청합니다.
물론 이 방법도 나름의 장점이 있지만 문서 데이터베이스를 사용하는 가장 효율적인 방법과는 거의 정반대입니다.
사람들이 답변을 기다리게 하지 마세요
문서 데이터베이스를 모델링할 때 가장 먼저 하는 일은 "데이터에 대해 어떤 질문을 하고 싶은가?"를 묻는 것입니다.
그런 다음 시스템 상태가 변경되면 해당 질문에 대한 답을 계산하여 데이터베이스에 미리 저장합니다.
쿼리할 때마다 답을 다시 짜맞추는 대신, 한 번의 조회로 데이터베이스에서 완전한 형태의 답을 가져옵니다.
실제로는 어떤 의미일까요?
스웨그 관리의 예로 돌아가 보겠습니다. 질문 중 하나는 다음과 같습니다:
특정 주문을 처리하려면 어떻게 해야 하나요?
관계형 데이터베이스에서는 주문을 찾는 SQL 쿼리를 작성하고, 조인을 사용하여 주문의 항목을 찾은 다음, 각 항목의 세부 정보를 찾기 위해 또 다른 조인을 사용하고, 고객 세부 정보를 찾기 위해 추가 조인을 사용합니다.
Couchbase를 사용하면 다음과 같이 보일 것입니다:
- 사용자가 상품을 선택하고 주문합니다.
- 저희 시스템은 주문을 하나의 문서로 데이터베이스에 기록합니다.
- 주문 세부 정보를 가져와야 할 때 한 번만 읽으면 모든 정보를 파악할 수 있습니다.
결과 주문 문서는 다음과 같이 보일 수 있습니다:
"orderID": 200,
"고객":
{
"이름": "매튜 레벨",
"주소": "11-21 폴 스트리트",
"도시": "London"
},
"제품":
[
{
"itemCode": "RedTShirt",
"itemName": "레드 카우치베이스 티셔츠",
"수량주문": 3
},
{
"itemCode": "USB",
"itemName": "빨간색 카우치베이스 로고가 있는 검은색 8GB USB 스틱",
"수량 주문": 51
}
],
"상태": "유료"
}
이 예는 상당히 정규화되어 있습니다. 스웨그 관리 시스템에는 이미 각 고객과 제품에 대한 세부 정보가 별도의 문서에 있지만, 여기에 세부 정보를 포함시켜 고객에 대해 알고 있는 내용을 반복하고 있습니다.
향후 게시물에서 데이터 임베딩과 데이터 참조의 장단점에 대해 살펴보겠습니다.
프로덕션은 더 복잡합니다.
프로덕션 시스템에서는 이러한 기성 답변 중 몇 가지를 생성할 수 있을 것입니다. 깊이 생각하지 않고도 스웩 관리 시스템을 위해 몇 가지를 생각해낼 수 있을 것입니다:
- 고객 주문 내역: 고객은 자신이 주문한 모든 내용을 다시 보기를 원하므로 해당 주문에 대한 기록을 남깁니다.
- 실시간 주문 상태: 마찬가지로 고객은 주문 상태를 확인하고자 할 것이므로 지금 해당 정보를 생성한 다음 변경 사항이 있을 때마다 업데이트할 수 있습니다.
- 발송 지침: 창고에 있는 직원들에게 어디로 보내야 하는지 알려줘야 합니다.
중요한 것은 사람이 응답을 기다리는 동안 이 모든 것을 생성할 필요가 없다는 것입니다.
고객이 주문이 기록되었는지 확인할 수 있도록 고객의 실시간 주문 상태를 즉시 업데이트하고 싶을 수도 있지만, 발송 지시를 비동기적으로 처리하는 것도 괜찮습니다.
이렇게 하면 사람이 시스템에서 무언가를 볼 때 이미 데이터가 대기하고 있습니다.
요약: 답안 미리 계산하기
효율적인 문서 데이터베이스 모델링을 위한 첫 번째 단계는 답을 미리 계산하는 것입니다.
우리는 어떤 질문을 하고 싶은지 미리 알고 있으므로 데이터를 작성하는 방식에서 이러한 질문을 충족시킬 수 있습니다.
순수하고 정규화된 수학적으로 건전한 데이터 표현이라는 아이디어에는 많은 지적 매력이 있지만, 실제로는 다수의 동시 사용자에게 서비스를 제공하고 수요 변화에 따라 운영을 확장하는 것이 더 어려워질 수 있습니다.
작성 시점에 다양한 답변을 계산해 보았습니다:
- 사용자 경험에서 지연 제거
- 클러스터 전체에 데이터를 더 쉽게 배포할 수 있습니다.
- 를 사용하면 객체 상태와 데이터베이스의 불일치가 줄어든다는 추가 보너스를 얻을 수 있습니다.
다음 시간에는 언제 데이터를 삽입하고 언제 데이터를 참조해야 하는지에 대해 살펴보겠습니다.
각 아이템의 주문량을 확인해야 할 필요가 있다는 사실을 사후에 깨닫는 것과 같은 사소하지 않은 사례라도 이 시리즈에 포함시키길 바랍니다(증분 맵 감소 가능).
고객 정보가 8백만 개의 다른 장소에 저장되어 있는 경우 어떻게 고객 정보를 업데이트할 수 있을까요?
800만 개의 서로 다른 위치에서 동일한 데이터를 참조하고 동기화되지 않아야 하는 경우, 해당 데이터의 표준 기록을 보관하고 필요한 800만 개의 위치에서 각각 참조하는 것이 거의 확실합니다.
별도의 문서에 보관해야 하고 일관성을 유지해야 하는 데이터의 사본이 많은 경우 가장 쉬운 방법은 N1QL 쿼리일 것입니다.
그렇다면 파트 2가 있나요?
2부는 여기에 있습니다: https://www.couchbase.com/data-modelling-when-embed-or-refer/