DynamoDB의 키 오버로딩
SQL에서 열은 영원히 한 가지를 의미합니다. orders.created_at은 항상
날짜, users.email은 항상 이메일입니다. 키 오버로딩으로 인해 해당 내용이 삭제됩니다. 당신
파티션과 에 일반 이름(pk, sk)을 지정하고 각 항목이 유형을 갖도록 합니다.
거기에 다른 의미를 부여해보세요. 하나의 테이블, 많은 엔터티, 하나의 모양.
DynamoDB의 키 오버로드란 무엇입니까?
키 오버로딩은 pk/sk와 같은 일반 키 이름으로 하나의 테이블에 여러 엔터티 유형을 저장하고 해당 유형을 값(USER#u_3001, INVOICE#2026-0014)으로 인코딩하는 것입니다. 속성 이름은 중립으로 유지되므로 사용자, 청구서 및 이벤트가 하나의 파티션을 공유합니다. 값은 유형을 전달하고 정렬 키 접두사는 begins_with를 통해 각 항목을 하나의 Query 슬라이스로 허용합니다.
- 일반 키 이름, 입력된 값. 키 이름을
pk/sk로 지정하고 엔터티를 입력합니다. 값:pk = "TENANT#acme",sk = "USER#u_3001"을 입력합니다. 이름이 멍청하네요; 값은 유형을 전달합니다. - 단일 테이블 디자인이 작동하는 이유입니다. 과부하 없이 공유 테이블
그냥 쓰레기 서랍일 뿐이야. 이를 통해 모든 엔터티는
Query할 수 있는 파티션에 위치합니다. begins_with는 결과입니다. 정렬 키의 유형 접두어를 사용하면QueryScan이나 필터 없이 전체 엔터티 또는 그 중 한 조각을 가져옵니다.- 비용: 가독성. 원시
pk/sk덤프는 아무 것도 알려주지 않습니다. 당신은 접두사를 해독하는 뷰어가 아니면 문자열을 눈을 가늘게 뜨고 보게 될 것입니다.
일반적인 이름이 실제 이름보다 나은 이유
DynamoDB는 테이블당 최대 2개의 주요 속성을 제공하며 Query는
단일 파티션 키. 따라서 키 이름을 userId로 지정하면 사용자 항목만
그 테이블은 깔끔하게 — 다른 모든 것은 userId를 가짜로 만들거나 자체 테이블로 이동해야 합니다.
과부하는 이를 회피합니다. pk과 같은 중립적인 이름은 어떤 개체에도 적용되지 않습니다.
따라서 사용자, 송장 및 감사 이벤트는 모두 동일한 키 속성을 공유할 수 있으며
같은 테이블. 속성 이름이 아닌 값은 항목이 무엇인지 나타냅니다.
이것은 에서 single-table design로 바뀌는 움직임입니다. 이론을 실제로 쿼리할 수 있는 것으로 변환합니다. 공유 테이블은 컨테이너입니다. 오버로딩은 별개의 개체가 내부에 공존할 수 있도록 하는 것입니다.
다중 테넌트 예
SaaS 청구 제품을 운영한다고 가정해 보겠습니다. 각 테넌트에는 회원, 송장 및 감사가 있습니다. 흔적. 세 개의 테이블 대신 모든 테이블을 하나에 넣고 키를 오버로드하세요.
| pk | sk | attributes |
|---|---|---|
| TENANT#acme | META | name="Acme Inc", plan="team" |
| TENANT#acme | USER#u_3001 | email, role="admin" |
| TENANT#acme | USER#u_3002 | email, role="member" |
| TENANT#acme | INVOICE#2026-0014 | amount_cents, status="paid" |
| TENANT#acme | INVOICE#2026-0015 | amount_cents, status="open" |
| TENANT#acme | EVENT#2026-06-23T09:12Z | actor="u_3001", action="invite" |
모든 행은 pk = "TENANT#acme"을 공유하므로 하나의 을 형성합니다 — 모두
같은 위치에 있으며 단일 파티션 읽기로 모두 연결할 수 있습니다.
정렬 키 접두사가 실제 작업을 수행합니다. 엔터티를 그룹화하고 주문합니다.
오버로드된 컬렉션 쿼리
유형이 정렬 키 접두사에 있으므로 begins_with는 파티션을 다음과 같이 분할합니다.
아무것도 스캔하지 않고 엔터티:
Query pk = "TENANT#acme" -- the entire tenant, every type
Query pk = "TENANT#acme" AND begins_with(sk, "USER#") -- just members
Query pk = "TENANT#acme" AND begins_with(sk, "INVOICE#") -- just invoices
전체 파티션이 아닌 조건과 일치하는 항목에 대해서만 비용을 지불합니다.
행을 읽으려면 비용을 지불하는 필터링된 Scan의 반대
그런 다음 버립니다. AWS에서는 이를 핵심 조건이라고 부릅니다. 이전에 키에서 실행됩니다.
모든 데이터가 파티션을 떠납니다.
해당 begins_with 조건을 손으로 작성하는 경우 유형 태그를 올바르게 얻으십시오.
USER# 대신 USERS#는 아무 것도 반환하지 않습니다. 는
expression builder은 다음을 생성합니다.
KeyConditionExpression 및 ExpressionAttributeValues 지도이므로 접두사는
실제로 쓴 것과 일치합니다.
인덱스도 오버로드
동일한 방법이 에도 적용됩니다. 일반적인 키 이름을 지정하세요 — gsi1pk, gsi1sk —
그리고 각 엔터티가 필요한 것을 무엇이든 쓰도록 하세요. 그러면 하나의 인덱스가 패턴에 답합니다.
기본 테이블은 할 수 없습니다.
| pk | sk | gsi1pk | gsi1sk |
|---|---|---|---|
| TENANT#acme | INVOICE#2026-0015 | STATUS#open | 2026-06-30 |
| TENANT#acme | INVOICE#2026-0014 | STATUS#paid | 2026-06-12 |
| TENANT#beta | INVOICE#2026-0099 | STATUS#open | 2026-06-25 |
이제 Query gsi1 WHERE gsi1pk = "STATUS#open"에는 모든 미결 송장 이 나열됩니다.
테넌트, 기한순 — 기본 테이블의 테넌트 범위에 대한 파티션 간 보기
키는 절대 게재될 수 없습니다. 다른 엔터티는 자신의 의미로 gsi1를 재사용할 수 있습니다.
(예: gsi1pk = "ROLE#admin"), 하나의 인덱스가 여러 읽기를 포괄합니다. 그냥 기억해
GSI는 eventually consistent - 쓰기가 기본 테이블보다 지연됩니다.
DynoTable에서 해보기
원시 오버로드된 키는 읽기에 적대적입니다: INVOICE#2026-0015 및
EVENT#2026-06-23T09:12Z 평면 목록에서 함께 흐리게 표시됩니다. 기준으로 그룹화된 뷰어
접두사를 분할하고 표면화하면 정크 서랍을 다시 엔터티로 바꿉니다.

함정
- 구분 기호를 한 번 선택하고 절대 변경하지 마세요.
#가 관례입니다. 혼합#그리고 엔터티 전체의:는 아무 것도 경고하지 않는 방식으로begins_with를 깨뜨립니다. - 범위 계산이 필요한 값을 오버로드하지 마세요.
INVOICE#2026-0015는 숫자가 아닌 어휘순으로 정렬 — 30개의 ID 및 ISO-8601 사용 문자열 순서가 사용자가 의미하는 순서와 일치하도록 날짜를 지정합니다. - 접두사 네임스페이스를 예약합니다. 둘 다
USER로 시작하는 두 가지 엔터티 유형(예:USER#및USERGROUP#)는begins_with(sk, "USER")아래에서 충돌합니다. 확인 첫 번째 문자부터 명확한 접두사. - 키 이전에 읽기를 계획합니다. 오버로드는 사용자가 선택한 액세스 패턴을 제공합니다. 열거. 아직 읽은 내용을 모른다면 다음을 참조하세요. single-table design 첫 번째 — 키가 다운스트림입니다. 쿼리의.
파티션을 매핑한 다음 download DynoTable로 나만의 파티션을 찾아보세요. 과부하된 열쇠를 보고 하나가 전체 세입자를 한꺼번에 끌어당기는 것을 지켜보세요.
과부하된 파티션의 쿼리 비용
TENANT#acme 아래의 모든 구성원 나열
begins_with(sk, "USER#")는 사용자 행만 읽으며 송장이나 이벤트는 읽지 않습니다.
데이터가 파티션을 떠나기 전에 키 조건이 필터링되기 때문입니다. 세입자에게
사용자가 200명(각각 2KB)이고 감사 이벤트가 5,000개(각각 1KB)인 경우 해당 쿼리는
최대 400KB(최대 100개의 최종 일관성 RCU)에 도달합니다. 테이블 전체에 Scan
사용자를 찾으려면 모든 테넌트의 모든 항목을 측정해야 합니다.
오버로드된 대표 항목을 item-size calculator, 견적 목록 pricing calculator에 쿼리합니다.
단일 테이블 도구를 사용한 디자인
엔터티(테넌트, 사용자, 송장, 이벤트) 및 액세스 패턴("사용자 나열")을 입력합니다.
테넌트용", "테넌트 전체에 대한 청구서 열기")를
single-table design tool. 제안한다
사용할 과부하 접두어와 일치하는 pk/sk 템플릿 및 GSI 키
프로덕션에서 — CloudFormation을 커밋하기 전.
패턴에서 쿼리 내보내기
접두사가 수정되면
expression builder 및 페이지가 매겨진 파일을 내보냅니다.
query builder의 프로그램. 접두사 오타
(USER# vs USERS#) 오류 없이 빈 집합 반환 — 생성된 표현식
조용한 실패 모드를 줄이세요.
엔터티 유형 접두사 레지스트리
개발자가 참조할 수 있는 짧은 내부 테이블을 유지하십시오.
| 엔터티 | 접두사 정렬 | 예시 SK | 쿼리 조각 |
|---|---|---|---|
| 테넌트 메타 | META | META | 단일 항목 가져오기 |
| 사용자 | USER# | USER#u_3001 | begins_with(sk, "USER#") |
| 송장 | INVOICE# | INVOICE#2026-0015 | begins_with(sk, "INVOICE#") |
| 이벤트 | EVENT# | EVENT#2026-06-23T09:12Z | 내림차순 읽기가 있는 시간순 꼬리 |
새로운 엔터티 유형은 begins_with에서 충돌하지 않는 접두사를 선택해야 합니다.
기존 접두사 — USER# 및 USERGROUP#는 모두 begins_with(sk, "USER")를 늘리거나 구분 기호로 주의 깊게 분리하지 않는 한.


