DynamoDB의 비정규화
SQL에서 보면 비정규화는 죄악처럼 들립니다. 데이터가 중복되고 단일 데이터가 없습니다. 진실의 근원. DynamoDB에서는 이것이 핵심입니다. 조인이 없으므로 관련 데이터를 필요한 항목에 복사하고 한 번에 다시 읽어보세요.
DynamoDB의 비정규화란 무엇입니까?
DynamoDB의 비정규화는 관련 데이터를 읽는 항목에 복사하는 것을 의미하므로 단일 쿼리가 모든 것을 한 번에 반환합니다. DynamoDB에는 조인이 없기 때문에 읽기 시 테이블을 함께 연결하는 대신 쓰기 시 미리 조인합니다. 단점은 부실함입니다. 거의 변경되지 않는 중복 값만 존재합니다.
- 조인이 없다는 것은 쓰기 시 사전 조인을 의미합니다. 관련 값을 이를 읽는 항목이므로 쿼리에 두 번째 조회가 필요하지 않습니다.
- 두 가지 특징. 한 항목의 복잡한 속성에 중첩된 데이터를 삽입하거나 여러 항목에 걸쳐 값을 중복합니다.
- 발총은 진부합니다. 소스가 변경되면 모든 복사본이 잘못됩니다. 업데이트를 팬아웃할 때까지. 거의 변경되지 않는 중복 값만.
- 쓰기가 아닌 읽기를 구매합니다. 더 많은(그리고 더 신중한) 쓰기를 위해 거래합니다. 저렴한 단일 요청 읽기.
대체할 조인이 없는 이유
관계형 JOIN은 읽기 시 정규화된 행을 재조립합니다. DynamoDB에는 없습니다.
조인 — a Query는 1 을 읽고 저장된 내용을 정확히 돌려줍니다.
거기. 두 테이블을 하나로 묶는 것은 없습니다. (생산 읽기에
어쨌든 경로 - 임시 감사 또는 드리프트 확인의 경우 DynoTable's SQL
Workbench는 DynamoDB 클라이언트 측에서 실제 JOIN를 실행합니다.)
따라서 데이터는 읽기를 위해 이미 형성되어 있어야 합니다. 화면에 게시물이 필요한 경우 작성자의 이름, 해당 이름은 읽은 게시물이 이미 접촉한 어딘가에 있어야 합니다. 2007년 Amazon Dynamo 논문에서는 이러한 거래를 명시적으로 설명했습니다. 관계형 기능을 삭제합니다. 대규모로 예측 가능한 읽기를 얻기 위해 — DynamoDB 거래는 이제 다음과 같은 기능을 제공합니다. 한 자리 밀리초 단위로 읽습니다.
패턴 1 - 복잡한 속성 포함
DynamoDB 속성은 스칼라뿐만 아니라 중첩된 맵 및 목록을 보유할 수 있습니다. 그래서 일반적인 비정규화 형태 중 하나는 하위 객체를 해당 객체 내부에 직접 채우는 것입니다. 자체 항목을 제공하는 대신 상위 항목을 제공합니다.
태그와 작은 작성자 스냅샷이 모두 하나의 항목에 포함된 게시물:
| PK | SK | author | tags |
|---|---|---|---|
| POST#9f3 | META | {id: U#12, name: "Mara Vance"} | ["dynamodb","aws"] |
하나의 GetItem은 게시물, 태그 및 작성자 블록을 함께 반환합니다. 아니요
두 번째 읽음. 이는 상위가 소유하고 경계가 지정된 데이터에 적합합니다.
크기 — 소수의 태그, 작성자 스냅샷 1개.
준수 한계: 단일 DynamoDB 항목의 최대치는 400KB, 속성입니다. 이름과 값이 포함됩니다(Service Quotas). 무제한 목록(바이럴 게시물의 모든 댓글)을 삽입하면 이를 뛰어넘을 수 있습니다.
패턴 2 - 항목 전체에 값 복제
블로그 사례는 교과서 사례입니다. 게시물을 나열하고 각 행에 작성자의 표시 이름 - 하지만 이를 가져오기 위해 게시물당 두 번째 읽기를 원하지 않습니다.
따라서 게시물이 생성될 때 각 게시물 항목에 작성자의 이름을 적습니다.
| PK | SK | authorId | authorName | title |
|---|---|---|---|---|
| POST#9f3 | META | U#12 | "Mara Vance" | "Modeling 1:N" |
| POST#a71 | META | U#12 | "Mara Vance" | "Sparse GSIs" |
| POST#b04 | META | U#88 | "Lio Tan" | "Query vs Scan" |
게시물 위에 (예: GSI1PK = "POST" 또는 작성자가 입력한 항목)은 전체를 렌더링합니다.
목록 — 제목 및 작성자 — 행별 조회가 없습니다. 파티션 키의 begins_with이(가) 아닙니다.
것; a Query에는 파티션 키 동일성이 필요하므로 포스트당 파티션 키를 사용하면 목록이 제공됩니다.
POST#보다 Query가 아닌 GSI에서 나온 것입니다. 작성자 이름은 비정규화되었습니다.
표준 사본은 USER#12에 있으며 모든 게시물에는 자체 사본이 있습니다.
거래가 바로 거기에 있습니다. N+1 읽기를 하나의 읽기로 전환했습니다.
N+1자리에 "Mara Vance"을 유지합니다.
삽입 vs. 중복 - 어느 것인가요?
| 포함(복합 속성) | 복제(항목 간 복사) | |
|---|---|---|
| 모양 | 하위가 상위 내부에 중첩됨 | 많은 품목에 대해 동일한 가치 |
| 제한된 부모 소유 데이터 | 많은 항목이 표시되는 공유 가치 | |
| 읽기 | 하나 GetItem | 하나 Query |
| 업데이트 비용 | 하나의 상위 항목 다시 작성 | 모든 사본에 팬 아웃 |
| 규모 위험 | 400KB 항목 한도 | 항목당 없음 |
자식이 부모와 함께만 나타나는 경우 삽입에 도달하세요. 도달하다 중복은 여러 독립 항목이 동일한 공유 값을 표시해야 하는 경우입니다.
풋건: 오래된 복사본
Mara는 자신의 이름을 "Mara V"로 바꿉니다. USER#12를 업데이트했습니다. 모든 게시물 항목은 여전히
고치러 갈 때까지 "Mara Vance"이라고 합니다.
따라서 중복된 값을 업데이트하는 것은 한 줄짜리가 아닌 팬아웃 쓰기입니다. 당신은 쿼리 영향을 받는 모든 항목을 확인하고 각각 다시 작성합니다. 행만 터치하면 이상적으로 보호됩니다. 여전히 이전 값을 유지합니다.
UPDATE POST#9f3
SET authorName = "Mara V."
WHERE authorName = "Mara Vance"
다음에서 authorName에 대해 조건부 SET을 구성할 수 있습니다.
Expression Builder 생성된 파일을 복사합니다.
UpdateExpression 및 ConditionExpression를 코드에 바로 입력하세요.
팬아웃 자체는 항목별 쓰기입니다. 해당 작성자의 작성자 키가 지정된 GSI를 쿼리합니다. 게시물을 작성한 후 업데이트를 발행하세요. 순서:
데이터 복제 비용: 소스에 대한 모든 변경은 쿼리와 쓰기로 이루어집니다. 사본 당. DynoTable에서 팬아웃은 staging area에 위치합니다. 먼저 검토 가능한 항목별 속성별 차이로 — 해당 항목의 모든 사본을 볼 수 있습니다. 배송되기 전에 곧 변경될 예정입니다.
이것이 규칙이 거의 변경되지 않는 중복 값만인 이유입니다. 디스플레이 이름, 계획 계층, 카테고리 라벨 — 괜찮습니다. 라이브 카운터 또는 자주 편집되는 필드 — 하지 마세요; 팬아웃이 당신을 산채로 잡아먹을 겁니다.
팬아웃 쓰기 비용
업데이트하는 각 복사본은 별도로 청구되는 쓰기입니다. us-east-1 온디맨드에서 작성자 이름 변경 후 게시물 항목 50개를 업데이트하면 50 × WCU — 각 게시 행이 ≤ 1 KB면 보통 항목당 1 WCU/KB — 가 듭니다. 읽기 쪽은 Query 한 번. 쓰기 쪽은 유지하는 복제 수에 비례해 늘어납니다. 두 경로를 요금 계산기로 추정하세요.
정규화가 여전히 성공하는 경우
값이 자주 변경되거나, 정말 예측할 수 없는 사람이 한 항목을 읽는 경우 패턴을 정규화한 상태로 유지하고 추가 읽기를 허용합니다. 비정규화는 알려진 읽기 중심 액세스 패턴에 대한 최적화 — 적용할 기본값은 아닙니다. 모든 곳에. 실제로 실행하는 읽기를 미리 조인하고 나머지는 그대로 둡니다.
이러한 중복된 속성이 어디에 있는지 결정하려면 액세스 패턴을 모델링하세요. 먼저 — single-table design를 참조하세요. 그리고 읽어보려면 거래 측면, Query vs Scan.
DynoTable 다운로드 비정규화된 테이블을 검사하기 위해, 복사되는 지점
드리프트하고 자신의 데이터에 대해 팬아웃 업데이트를 실행합니다. 그
SQL Workbench은 심지어 JOIN에 대한 진실의 원천이 될 수도 있습니다.
하나의 쿼리에서 드리프트를 찾기 위한 복사본입니다.