Node.js(AWS SDK v3)에서 DynamoDB GSI 쿼리하기

GSI 쿼리는 평범한 QueryIndexName을 더한 것이지만, 그 순간 두 가지가 테이블 쿼리처럼 동작하지 않게 됩니다. 익숙하던 일관성 플래그가 오류가 되고, 페이지네이션 커서에 속성이 하나 더 붙습니다. 여기서 AlbumTitle-index는 앨범으로 노래를 가져오는데, 기본 테이블(Artist + SongTitle)로는 Scan 없이 할 수 없는 일입니다.

코드

import {DynamoDBClient, QueryCommand} from '@aws-sdk/client-dynamodb';

const client = new DynamoDBClient({region: 'us-east-1'});

const items = [];
let lastEvaluatedKey;

do {
  const response = await client.send(
    new QueryCommand({
      TableName: 'Music',
      IndexName: 'AlbumTitle-index',
      KeyConditionExpression: '#hashKey = :hashKeyValue',
      ExpressionAttributeNames: {
        '#hashKey': 'AlbumTitle'
      },
      ExpressionAttributeValues: {
        ':hashKeyValue': {S: 'Danzon'}
      },
      ExclusiveStartKey: lastEvaluatedKey
    })
  );

  items.push(...(response.Items ?? []));
  lastEvaluatedKey = response.LastEvaluatedKey;
} while (lastEvaluatedKey);

console.log(`Found ${items.length} songs on the album`);

커서는 두 개가 아니라 세 개의 속성 폭입니다

한 앨범에 담긴 300곡을 상대로 위 루프를 실행하고, 돌려받은 LastEvaluatedKey를 살펴보세요:

table query  -> ['Artist', 'SongTitle']
GSI query    -> ['AlbumTitle', 'Artist', 'SongTitle']

GSI 키는 고유하지 않으므로 인덱스 키만으로는 스캔을 재개할 수 없습니다. DynamoDB는 인덱스 키 기본 테이블 키를 함께 반환하며, 둘 다 손대지 않은 채로 ExclusiveStartKey에 되돌아가야 합니다. 그래서 "마지막으로 본 정렬 키"를 저장하는 직접 만든 커서가 테이블에서는 동작하다가 인덱스에서는 조용히 항목을 잃거나 중복시키는 것입니다. 또한 테이블 키가 유출하고 싶지 않은 사용자 id일 때 그 키를 클라이언트에 저장하는 것이 나쁜 생각인 이유이기도 합니다.

ConsistentRead: true는 업그레이드가 아니라 400입니다

직관적으로는 강력한 일관성 읽기가 용량을 더 쓰고 더 신선한 데이터를 준다고 생각하게 됩니다. GSI에서는 요청 자체를 잃습니다:

ValidationException: Consistent reads are not supported on global secondary indexes
HTTP 400

API 레퍼런스도 똑같이 단호합니다. "Strongly consistent reads are not supported on global secondary indexes. If you query a global secondary index with ConsistentRead set to true, you will receive a ValidationException." GSI에 대한 Scan도 같은 메시지로 같은 플래그를 거부합니다. 로컬 보조 인덱스는 받아들입니다.

2026-07-28에 node v24.18.0에서 @aws-sdk/client-dynamodb 3.1095.0으로 DynamoDB Local(amazon/dynamodb-local)을 상대로 재현했습니다. 오류 텍스트와 키 형태는 엔진 자신의 출력입니다.

설명

  • IndexNameTableName을 대체하지는 않습니다. 둘 다 같은 명령에 들어가며, KeyConditionExpression은 테이블이 아니라 인덱스의 파티션 키(AlbumTitle)를 지목하고, 연산자 집합은 테이블 쿼리와 동일합니다.
  • 프로젝션된 것만 얻습니다. GSI 쿼리는 인덱스가 프로젝션한 것(ALL, KEYS_ONLY, 또는 INCLUDE 목록)을 반환하며, API 레퍼런스에 따르면 "global secondary index queries cannot fetch attributes from the parent table"입니다. 속성이 빠져 있다면 기본 키로 후속 GetItem을 하거나, 프로젝션을 넓혀 인덱스를 다시 만들어야 합니다.
  • 인덱스 키가 없는 항목은 아예 나타나지 않습니다. 그것이 희소 인덱스 패턴이며, 기능입니다. status = "OPEN"인 행만 인덱싱하면 GSI가 작게 유지됩니다. 또한 GSI 쿼리가 예상보다 적은 항목을 반환하면서 오류를 내지 않는 이유이기도 합니다.
  • 복제는 비동기이므로, 방금 테이블에 도착한 쓰기가 아직 인덱스에 없을 수 있습니다. 쓰기 후 읽기 경로에서는 빡빡한 루프로 재시도하기보다 그것을 감안해 설계하세요.

시각적으로 해보기

나중에 GSI를 추가하는 것은 이 사실을 비싸게 배우는 방법입니다. 단일 테이블 설계 플래너는 여러분의 액세스 패턴을 받아 어느 것에 인덱스 키가 필요하고 어느 것은 기본 테이블이 이미 처리하는지 계산해 줍니다.

테이블의 인덱스를 탐색하고 폼에서 GSI 쿼리를 페이지네이션된 그리드와 함께 실행하려면, DynoTable을 다운로드하세요.

관련 예제

참고 자료

이 요청을 시각적으로 만들기

무료 DynamoDB 쿼리 빌더에서 이 작업을 구성하세요 — 키 조건, 필터, 인덱스, Limit, 정렬 순서, 페이지네이션 루프 — 그리고 실행 가능한 SDK v3, CLI, boto3 프로그램으로 다시 복사하세요.

DynamoDB 쿼리 빌더 열기

Console 없이 DynamoDB 작업하기

DynamoDB로는 실행할 수 없는 진짜 SQL(JOINs, GROUP BY, 집계)을 실행하는 빠른 DynamoDB 데스크톱 클라이언트. 시각적 편집과 여러분 자신의 Bedrock 키로 동작하는 AI 에이전트를 제공합니다.

30일 무료 체험, 신용카드 불필요 — 이후 기간 제한 없는 무료 요금제.