중급4분 분량

변하는(가변) 속성으로 DynamoDB 정렬하기

어떤 속성 순서로 항목을 쿼리하려고 그 속성을 정렬 키로 모델링했는데 — 그 속성이 변합니다. 티켓의 상태, 주문의 상태, 작업의 우선순위처럼요. DynamoDB가 던지는 함정은 이것입니다: 키 속성은 제자리에서 업데이트할 수 없습니다. 기본 키는 항목의 수명 동안 불변입니다. 키의 일부인 값을 바꾸는 것은 항목을 편집하는 게 아니라 — 옮기는 것이며, DynamoDB는 그걸 명시적으로 하게 만듭니다.

DynamoDB 정렬 키를 변경할 수 있나요?

정렬 키는 기본 키의 일부이며, DynamoDB 키 속성은 불변입니다 — UpdateItem으로 파티션 키나 정렬 키 값을 수정할 수 없고, "항목 이동" 작업도 존재하지 않습니다. 변경하려면 기존 항목을 삭제하고 새 항목을 put하거나, 변동 값을 베이스 테이블 키에서 떼어 GSI 정렬 키에 올리세요 — GSI 키는 베이스 항목을 업데이트하면 자동으로 다시 전파됩니다.

  • 키 속성은 불변입니다. 파티션 키나 정렬 키 값을 UpdateItem할 수 없습니다 — DynamoDB에는 "항목 이동" 작업이 없습니다.
  • 키 값을 바꾸려면 옛 항목을 삭제하고 새것을 put합니다 — 원자적이도록 이상적으로는 트랜잭션 안에서요.
  • 더 나은 방법: 변동 값을 베이스 테이블 키에서 떼어 두고 대신 GSI 정렬 키에 올리세요 — GSI 키는 바꿀 수 있는데, 베이스 항목을 업데이트하면 인덱스 항목이 다시 전파되기 때문입니다.
  • 변하지 않는 정렬 키를 고르세요(타임스탬프, 불변 id) — 액세스 패턴이 허락하는 한 언제나.

문제: 정렬하고 싶은 상태가 계속 변함

지원 데스크를 운영하며 팀의 티켓을 상태 순으로 나열하고 싶어서 상태를 정렬 키에 넣는다고 합시다:

PK: TEAM#7   SK: STATUS#open#TICKET#8842

이제 티켓이 pending으로 옮겨 갑니다. 그저 정렬 키를 STATUS#pending#TICKET#8842UpdateItem하고 싶겠지만 — DynamoDB는 키 속성을 바꾸는 어떤 쓰기도 거부합니다. 키는 항목의 주소이므로, 주소를 제자리에서 편집할 수 없습니다. 정렬하려고 고른 상태가 바로 가만히 있지 않는 그것입니다.

옵션 1: 삭제하고 재생성하기(원자적으로)

값이 반드시 베이스 테이블 키에 있어야 한다면, 그것을 바꾸는 것은 옛 항목을 제거하고 새것을 쓰는 일입니다:

1. DeleteItem  PK=TEAM#7  SK=STATUS#open#TICKET#8842
2. PutItem     PK=TEAM#7  SK=STATUS#pending#TICKET#8842  (same attributes)

TransactWriteItems 안에서 해서 삭제와 put이 둘 다 성공하거나 둘 다 실패하게 하세요 — 그렇지 않으면 둘 사이의 크래시가 티켓을 잃거나 중복시킵니다. 동작하긴 하지만, 이제 모든 상태 변경이 두 번의 쓰기에 트랜잭션까지 더해집니다. 가끔의 변경엔 괜찮지만, 잦은 변경엔 비쌉니다.

옵션 2: 가변 값을 베이스 키에서 떼어 두기(권장)

더 깔끔한 설계: 베이스 테이블 키를 불변인 것(티켓 id)으로 만들고, 변동하는 정렬 가능한 값을 GSI 정렬 키에 올리세요.

Base:  PK: TICKET#8842   status: "open"   teamId: TEAM#7
GSI:   GSI1PK: TEAM#7    GSI1SK: STATUS#open#TICKET#8842

이제 상태를 바꾸는 것은 베이스 항목의 status 속성에 대한 평범한 UpdateItem입니다 — status는 베이스 테이블 키가 아니므로 DynamoDB가 허용합니다. 그러면 DynamoDB가 GSI 항목을 자동으로 새 정렬 위치로 다시 전파합니다. 한 번의 쓰기, 트랜잭션 없음, 삭제 춤도 없음.

아니오, GSI 정렬상태가 open에서 pending으로 변함값이 베이스 테이블 키에 있나?트랜잭션 안에서 삭제 + 재생성평범한 UpdateItem; GSI가 다시 전파

트레이드오프: GSI는 최종적 일관성이고 추가 스토리지/쓰기 비용이 듭니다 — 하지만 자주 바뀌는 값이라면, 변경마다 삭제-후-재생성하는 것보다 훨씬 저렴합니다.

DynoTable에서 키 설계하기

베이스 읽기와 GSI 읽기 양쪽의 키 조건을 DynamoDB 표현식 빌더로 만들고 미리 보세요.

DynoTable에서는 쿼리가 어느 인덱스를 통해 실행될지 직접 선택하고, 변동 값이 GSI에서 정렬되는 동안 베이스 항목은 불변 키를 유지하는 모습을 확인할 수 있습니다 — 실제 데이터를 바탕으로 두 읽기를 나란히 비교하면서요.

DynoTable에서 베이스 항목은 불변 키를 유지하면서 상태 정렬 GSI를 쿼리하기.
DynoTable에서 베이스 항목은 불변 키를 유지하면서 상태 정렬 GSI를 쿼리하기.

함정 + 다음 단계

  • 키 속성을 UpdateItem하려 하지 마세요 — 거부됩니다. 키 값은 항목의 수명 동안 고정입니다.
  • 꼭 옮겨야 한다면 트랜잭션 안에서 삭제+put하세요 — 결코 가드 없는 두 쓰기로 하지 마세요.
  • 정렬하면서 동시에 변형하는 속성에는 불변 베이스 키 + GSI를 선호하세요.
  • GSI 최종적 일관성을 잊지 마세요 — 다시 정렬된 항목은 짧은 전파 지연 후에 나타납니다.
  • 관련: 정렬 키 전략, GSI vs LSI, 트랜잭션.

가변 속성이 베이스 테이블 대 GSI에서 어떻게 정렬되는지 보고 싶으신가요? DynoTable을 받아 인덱스를 직접 탐색해 보세요.

업데이트됨