[ GSI 개념 ]
DyanmoDB는 기본키(PK) 기준으로 데이터를 조회하며
다양한 쿼리 패턴을 위해서는 추가적으로 인덱스가 필요합니다.
예를 들어 PK = user_id 로 지정했는데 age로 조회하고 싶을 경우,
작은 테이블에선 조회가 가능할지 모르지만 저장된 데이터가 클 경우 에러 혹은 검색이 되지 않습니다.
이럴 때 GSI나 LSI를 사용하면 데이터 복제 없이도 새로운 쿼리 경로를 생성할 수 있습니다.
아래는 DynamoDB에서 지원하는 인덱스 2가지 입니다.
- Global Secondary Index : 기본 키와 관계없이 다른 파키션 키와 정렬 키를 사용하는 인덱스
- Local Secondary Index : 기본 파키션 키는 유지하고 다른 정렬 키를 사용하는 인덱스
[ PK와 SK의 역할 ]
DynamoDB 테이블의 기본 키는 아래 두 가지 형태 중 하나로 정의된다:
- 단일 키: Partition Key만 존재 : 완전히 고유한 값으로만 조회 가능
- 복합 키: Partition Key + Sort Key 조합 : 파티션 키로 필터링한 후, 정렬 키로 정렬된 범위 쿼리 가능
Table: Users
Partition Key: user_id
Sort Key: position
→ 특정 유저의 포지션 별로 데이터를 쉽게 조회 가능
[ 기본 쿼리의 한계 ]
기본 키가 아닌 속성으로는 직접 조회가 불가능하거나, 스캔(Scan) 연산이 발생합니다.
- 성능 저하: 전체 테이블을 읽는 스캔은 매우 비효율적
- 비용 증가: 읽은 모든 항목에 대해 비용 발생
- 응답 지연: 필터링이 클라이언트 또는 DynamoDB 내부에서 발생하므로 지연
그러므로 인덱스(GSI 또는 LSI)를 설계하여 다양한 쿼리가 가능하게 구현합니다.
[ GIS (Global Secondary Index ) ]
GSI 생성
AWS DynamoDB Console에서 GSI를 생성합니다.
속성 프로젝션
GSI( 또는 LIS)를 만들 때 선택하는 속성 프로젝션(Attribute Projection)은
인덱스에 어떤 데이터를 저장할지 결정합니다.
다시 말해 인덱스만 보고 원하는 데이터를 얻을 수 있는지,
기본 테이블 컬럼 값까지 다시 조회해야 하는지에 영향을 줍니다.
예제 테이블 Employee ( PK = emp_id )
aws dynamodb create-table \
--table-name Employee \
--attribute-definitions \
AttributeName=emp_id,AttributeType=S \
AttributeName=department,AttributeType=S \
--key-schema AttributeName=emp_id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST
ALL 옵션
all 옵션으로 GSI를 생성할 경우 인덱스에 모든 속성이 포함되어 있어서 바로 조회가 가능합니다.
쿼리만으로 모든 속성 조회가 가능하지만, 인덱스가 커짐에 따라 쓰기 비용이 증가합니다.
# 생성
aws dynamodb update-table \
--table-name Employee \
--attribute-definitions AttributeName=department,AttributeType=S \
--global-secondary-index-updates \
'[{
"Create": {
"IndexName": "GSI_All",
"KeySchema": [{"AttributeName":"department","KeyType":"HASH"}],
"Projection": {"ProjectionType":"ALL"}
}
}]'
# 조회
aws dynamodb query \
--table-name Employee \
--index-name GSI_All \
--key-condition-expression "department = :dept" \
--expression-attribute-values '{":dept": {"S": "Engineering"}}'
KEYS_ONLY 옵션
GSI로 조회한 속성이 기본키가 아닌 경우에는 한번 더 조회가 필요합니다.
기본키만 저장되므로 저장 효율이 높지만, 추가 조회가 필요할 수 있습니다.
# 생성
aws dynamodb update-table \
--table-name Employee \
--global-secondary-index-updates \
'[{
"Create": {
"IndexName": "GSI_KeysOnly",
"KeySchema": [{"AttributeName":"department","KeyType":"HASH"}],
"Projection": {"ProjectionType":"KEYS_ONLY"}
}
}]'
# 조회
# 1단계: 인덱스에서 기본 키 조회
aws dynamodb query \
--table-name Employee \
--index-name GSI_KeysOnly \
--key-condition-expression "department = :dept" \
--expression-attribute-values '{":dept": {"S": "Engineering"}}'
# 2단계: 반환된 emp_id로 본 테이블에서 전체 정보 조회
aws dynamodb get-item \
--table-name Employee \
--key '{"emp_id": {"S": "e001"}}'
INCLUDE 옵션
name과 position은 바로 조회가 가능하며 다른 속성은 key_only옵션처럼 본테이블에서 조회가 필요합니다.
# 생성
aws dynamodb update-table \
--table-name Employee \
--global-secondary-index-updates \
'[{
"Create": {
"IndexName": "GSI_Include",
"KeySchema": [{"AttributeName":"department","KeyType":"HASH"}],
"Projection": {
"ProjectionType":"INCLUDE",
"NonKeyAttributes":["name", "position"]
}
}
}]'
# 조회
aws dynamodb query \
--table-name Employee \
--index-name GSI_Include \
--key-condition-expression "department = :dept" \
--expression-attribute-values '{":dept": {"S": "Engineering"}}'
[ LSI (Local Secondary Index) ]
LSI 생성
유저 활동의 로그 테이블
# Table Name: UserActivityLog
# Partition Key: user_id
# Sort Key: activity_time
# LSI: (Sort Key로 action_type 추가)
aws dynamodb create-table \
--table-name UserActivityLog \
--attribute-definitions \
AttributeName=user_id,AttributeType=S \
AttributeName=activity_time,AttributeType=S \
AttributeName=action_type,AttributeType=S \
--key-schema \
AttributeName=user_id,KeyType=HASH \
AttributeName=activity_time,KeyType=RANGE \
--local-secondary-indexes \
'[{
"IndexName": "ActionTypeIndex",
"KeySchema": [
{"AttributeName": "user_id", "KeyType": "HASH"},
{"AttributeName": "action_type", "KeyType": "RANGE"}
],
"Projection": {
"ProjectionType": "ALL"
}
}]'
LSI 조회
action_type 기준으로 조회
- PK + SK 의 조합이 아닌 PK + LSI 키로 조회 가능
aws dynamodb query \
--table-name UserActivityLog \
--index-name ActionTypeIndex \
--key-condition-expression "user_id = :uid AND action_type = :atype" \
--expression-attribute-values '{
":uid": {"S": "user123"},
":atype": {"S": "login"}
}'
LSI 주의점
- 테이블 생성 시에만 정의 가능 : 반드시 처음에 정의해야 합니다.
- 같은 파티션 내 10GB 제한 : 하나의 파티션 키에 대한 총 크기가 10GB를 넘을 수 없습니다.
- 파티션 키는 동일 : LSI는 테이블의 PK와 같은 값을 공유합니다.
- 쓰기비용 : LSI도 데이터 복제가 필요하므로 쓰기 비용이 증가할 수 있습니다.
[ GSI와 LIS 차이 ]
항목 | GSI | LSI |
Partition Key | 기본 테이블과 달라도 됨 | 기본 테이블의 PK와 같고 SK만 다르게 지정 |
생성 시점 | 언제든지 | 테이블 생성시에만 |
저장 위치 | 테이블과 별로도 저장 | 기본 테이블과 같은 파티션에 저장 (10GB 제한) |
처리량 | GSI 별도로 설정 또는 On-demand로 처리 가능 | 기본 테이블의 처리량을 공유함 |
쿼리 성능 | 다양한 키 조합 쿼리 가능 | 같은 PK내에서 다른 SK로 조회 |
비용 | GSI 당 별도 비용 | 추가 비용 없음 |
[ 적용 예시 ]
테이블 스키마
PK: user_id
SK: timestamp
예시 1) 특정 유저의 특정 활동 유형만 조회
LSI: activity_type 로 지정
조회시 아래 키 사용
PK = user_id,
SK = activity_type
예시 2) 특정 직무에서 월급이 높은 순으로 조회
GSI: position, salary 지정
조회 시 아래 키 사용
PK=position,
SK=salary
'Platform > AWS' 카테고리의 다른 글
AWS - DynamoDB Pagination과 Where절 (0) | 2025.03.23 |
---|---|
AWS - Athena 날짜관련 함수 (0) | 2025.03.19 |
AWS - REST API 설정 가이드 (0) | 2024.09.22 |
AWS - Lambda VPC를 사용하여 고정 IP 주소 생성 (0) | 2024.08.28 |
AWS - Lambda Runtime 실행환경 (0) | 2024.08.28 |