DynamoDB 정렬 키를 사용하여 데이터를 정리하는 모범 사례

Dan.kimhaejun·2021년 3월 23일
0

Development

목록 보기
2/3

DynamoDB

  • NoSQL 데이터베이스

구성요소

테이블

– 다른 데이터베이스 시스템과 마찬가지로 DynamoDB는 데이터를 테이블에 저장합니다. 테이블은 데이터 모음입니다. 예를 들어, 친구, 가족 또는 기타 관심 있는 사람에 대한 개인 연락처 정보를 저장하는 데 사용할 수 있는 People이라는 예제 테이블을 참조하십시오. 또한 Cars 테이블에 사람들이 운전하는 차량에 대한 정보를 저장할 수도 있습니다.

항목

– 각 테이블에는 0개 이상의 항목이 있습니다. 항목은 모든 다른 항목 중에서 고유하게 식별할 수 있는 속성의 그룹입니다. People 테이블에서 각 항목은 한 사람을 나타냅니다. Cars 테이블의 경우 각 항목은 차량 한 대를 나타냅니다. DynamoDB의 항목은 여러 가지 면에서 다른 데이터베이스 시스템의 행, 레코드 또는 튜플과 유사합니다. DynamoDB에서는 테이블에 저장할 수 있는 항목의 수에 제한이 없습니다.

속성

– 각 항목은 하나 이상의 속성으로 구성됩니다. 속성은 기본적인 데이터 요소로 더 이상 나뉠 필요가 없습니다. 예를 들어 People 테이블의 항목에는 PersonID , LastName , FirstName등의 속성이 포함되어 있습니다. Department 테이블의 경우 항목에 DepartmentID , Name, Manager 등의 속성이 있을 수 있습니다. DynamoDB의 속성은 여러 가지 면에서 다른 데이터베이스 시스템의 필드 또는 열과 유사합니다.

기본 키

테이블을 생성할 때는 테이블 이름 외에도 테이블의 기본 키를 지정해야 합니다. 기본 키는 테이블의 각 항목을 나타내는 고유 식별자입니다. 따라서 두 항목이 동일한 키를 가질 수는 없습니다.

DynamoDB는 두 가지의 기본 키를 지원합니다.

파티션 키

  • 파티션 키.로 알려진 하나의 속성으로 구성되는 단순 기본 키.
  • 파키션 키는 유일해야 한다.

DynamoDB는 내부 해시 함수에 대한 입력으로 파티션 키 값을 사용합니다. 해시 함수 출력에 따라 항목을 저장할 파티션(DynamoDB 내부의 물리적 스토리지)이 결정됩니다.

파티션 키로만 구성되어 있는 테이블에서는 어떤 두 개의 테이블 항목도 동일한 파티션 키 값을 가질 수 없습니다.

에 설명된 People 테이블은 단순 기본 키테이블, 항목 및 속성PersonID()가 있는 테이블의 예입니다. People 테이블에 있는 항목의 PersonId 값을 입력하면 해당 항목에 직접 액세스할 수 있습니다.

티션 키 및 정렬 키

  • 복합 기본 키로 지칭되는 이 형식의 키는 두 개의 속성으로 구성됩니다. 첫 번째 속성은 파티션 키이고, 두 번째 속성은 정렬 키.입니다.
  • 파티션 키는 중복 가능, 정렬 키는 유일해야 한다.

DynamoDB는 내부 해시 함수에 대한 입력으로 파티션 키 값을 사용합니다. 해시 함수 출력에 따라 항목을 저장할 파티션(DynamoDB 내부의 물리적 스토리지)이 결정됩니다. 파티션 키 값이 동일한 모든 항목은 정렬 키 값을 기준으로 정렬되어 함께 저장됩니다.

파티션 키와 정렬 키로 구성되어 있는 테이블에서는 두 개의 항목이 동일한 파티션 키 값을 가질 수 있습니다. 그러나 두 아이템의 정렬 키 값은 달라야 합니다.

에 설명된 Music 테이블은 복합 기본 키가 있는 테이블의 테이블, 항목 및 속성 예입니다(Artist 및 SongTitle). 해당 항목에 Artist 및 값을 제공하면 SongTitleMusic 테이블의 모든 항목에 직접 액세스할 수 있습니다.

복합 기본 키를 사용하면 보다 유연하게 데이터를 쿼리할 수 있습니다. 예를 들어, Artist 값만 제공하는 경우 는 해당 아티스트의 모든 노래를 DynamoDB 검색합니다. 특정 아티스트의 노래 하위 집합만 가져오려면 Artist 값과 값의 범위만 입력하면 SongTitle됩니다.

참고

항목의 파티션 키를 해시 속성.이라고도 합니다. 해시 속성이라는 용어는 파티션 키 값에 따라 데이터 항목을 파티션에 균등하게 분산DynamoDB시키는 의 내부 해시 함수를 사용하는 것에서 유래합니다.

항목의 정렬 키를 범위 속성.이라고도 합니다. 범위 속성이라는 용어는 가 동일한 파티션 키가 물리적으로 서로 가까운 항목을 정렬 키 값에 따라 정렬된 순서로 DynamoDB 저장하는 방식에서 유래합니다.

각 기본 키 속성은 스칼라여야 합니다(즉, 단일 값만 가질 수 있음). 기본 키 속성에 허용되는 데이터 형식은 문자열, 숫자 또는 이진수뿐입니다. 다른 키가 아닌 속성에는 이러한 제한이 없습니다.

Pain Point

하나의 정렬이 아닌 여러개의 정렬 기능을 한번에 하고 싶다.
예) 좋아요 순 → 별점 순 → 최신 순
→ 좋아요가 같으면 별점인 높은 순, 별점도 같으면 최신 순

DynamoDB는 한번에 다중 정렬 기능을 지원하지 않는다.

어떻게 하면 내가 원하는 대로 정렬할 수 있을까?

Answer

복합 정렬 키 활용

Amazon DynamoDB 테이블에서 테이블의 각 항목을 고유하게 식별하는 기본 키를 파티션 키는 물론 일종의 정렬 키로 구성할 수 있습니다.

잘 설계된 정렬 키에는 중요한 장점이 두 가지 있습니다.

  • 효율적으로 쿼리를 할 수 있는 단일 장소로 관련 정보를 수집합니다. 신중하게 정렬 키를 설계하면 begins_withbetween>< 등 연산자를 사용하는 범위 쿼리를 사용하여 관련 항목의 필요한 그룹을 검색할 수 있습니다.

  • 복합 정렬 키는 계층 구조의 어느 수준에서 쿼리를 할 수 있도록 데이터의 계층적(일대다) 관계를 정의할 수 있도록 도와줍니다.

    예를 들어, 지리적 위치를 나열한 테이블에서 다음과 같이 정렬 키를 구성할 수 있습니다.

    [country]#[region]#[state]#[county]#[city]#[neighborhood]

    이렇게 하면 country부터 neighborhood까지, 그리고 그 사이의 집계 수준에서 위치 목록을 효율적으로 범위 쿼리할 수 있습니다.

How?

1. 데이터 설계시 다중 정렬이 필요한 사항을 고려하여 설계한다.

interface ProductReview {
	ID - pk //
	body - 리뷰 본문
	like - 좋아요 수
	score - 리뷰 스코어
	createdAt - 생성일자 timestamp
}

테이블 - ProductReview

  • ID - PK
  • body - 리뷰 본문
  • like - 좋아요 수
  • score - 스코어
  • createdAt - 생성일자 timestamp

2. 다중 정렬용 속성을 추가한다.

key

like#score#createdAt

value

like=5#score=5#createdAt=1600000000000

3. 유의사항 고려해서 value 값을 생성한다.

1) like의 자릿수가 다르다면 어떻게 관리할 것인가?

Question: 정렬 순서는 어떻게 될 것인가?

  • like=10#score=5#createdAt=1600000000000
  • like=200#score=5#createdAt=1600000000000
  • like=9#score=5#createdAt=1600000000000
  • like=31#score=5#createdAt=1600000000000

Expect: score, createdAt이 동일하기 때문에 like가 큰 순서대로 정렬될 것이다.

  • like=200#score=5#createdAt=1600000000000
  • like=31#score=5#createdAt=1600000000000
  • like=10#score=5#createdAt=1600000000000
  • like=9#score=5#createdAt=1600000000000

Result: 문자열 기준으로 정렬되기 때문에 첫번째 숫자가 큰 순서대로 정렬된다.

  • like=9#score=5#createdAt=1600000000000
  • like=31#score=5#createdAt=1600000000000
  • like=200#score=5#createdAt=1600000000000
  • like=10#score=5#createdAt=1600000000000

Solution - like의 자릿수를 맞춰준다 (ex - 00000200, 0000009)

  • pad라는 헬퍼 함수를 통해 자릿수를 맞춰주면서 해결할 수 있다.
  • 가능한 자릿수를 고려하여 기본 like 갯수에 0을 추가해준다.
const pad = (number: number, width: number) => {
  const stringNumber = String(number);
  return stringNumber.length >= width
    ? stringNumber
    : new Array(width - stringNumber.length + 1).join("0") + stringNumber;
};

Solution: padding 값을 활용하여 전체 like 자릿수를 맞춰준다.

  • like=00000200#score=5#createdAt=1600000000000
  • like=00000031#score=5#createdAt=1600000000000
  • like=00000010#score=5#createdAt=1600000000000
  • like=00000009#score=5#createdAt=1600000000000

2) 점수가 어쨌든 body가 있는 리뷰가 먼저 나왔으면 좋겠다.

Solution - body 유무에 따라 가장 앞에 value를 추가해준다.

  • body 가 있으면 1
  • body 가 없으면 0

Solution:

  • body=1#like=00000200#score=5#createdAt=1600000000000
  • body=1#like=00000031#score=5#createdAt=1600000000000
  • body=1#like=00000010#score=5#createdAt=1600000000000
  • body=1#like=00000009#score=5#createdAt=1600000000000
  • body=0#like=00000200#score=5#createdAt=1600000000000
  • body=0#like=00000031#score=5#createdAt=1600000000000
  • body=0#like=00000010#score=5#createdAt=1600000000000
  • body=0#like=00000009#score=5#createdAt=1600000000000

1) 의 상황은 Qoo10 에서 발생

  • 합의 후 결론 지음

2) 의 상황은 Shopee 에서 발생

  • 독단적 solution.. 괜찮나요?

결론

  • Data Utilization 이 자주, 많이 필요한 상황이라면 NoSQL은 지양할 것.
  • 그럼에도 불구하고 해결 방법은 있다.
  • 복합 정렬키를 활용하여 위기를 극복하자.
  • 상황에 따른 유연하고도 체계적인 DB 설계가 가장 중요하다.
profile
제가 겪은 이슈에 대해서 정리합니다. 기억보다는 기록이 더 낫다고 생각합니다.

0개의 댓글