Using Global Secondary Indexes in DynamoDB - Amazon DynamoDB

문서의 영문과 번역 사이에 충돌이 있는 경우에는 영문 버전을 따릅니다. 번역 버전은 기계 번역을 사용하여 제공합니다.

Using Global Secondary Indexes in DynamoDB

일부 애플리케이션은 서로 다른 속성을 쿼리 기준으로 사용하여 다양한 유형의 쿼리를 수행해야 할 수 있습니다. 이러한 요구 사항을 지원하기 위해 global secondary indexes 및 문제 Query 이 인덱스에 대한 요청 Amazon DynamoDB.

Scenario: Using a Global Secondary Index

모바일 게임 애플리케이션에서 사용자와 점수를 추적하는 GameScores라는 테이블을 예로 들어 설명해 보겠습니다. GameScores의 각 항목은 파티션 키(UserId)와 정렬 키(GameTitle)로 식별됩니다. 다음 그림은 테이블에서 항목을 구성하는 방식을 보여 줍니다. (일부 속성만 표시)


                사용자 ID, 타이틀, 점수, 날짜 및 승률의 목록이 포함되어 있는 GameScores 테이블입니다.

이제 각 게임의 최고 점수를 표시하는 순위표 애플리케이션을 작성하려는 경우를 가정하겠습니다. 키 속성(UserIdGameTitle)을 지정한 쿼리는 매우 효율적일 것입니다. 그러나 애플리케이션에서 GameTitle만을 토대로 GameScores에서 데이터를 검색해야 할 경우에는 Scan 작업을 사용해야 할 수 있습니다. 테이블에 항목을 추가할수록 전체 데이터 스캔이 느려지고 효율성이 저하되면서 다음과 같은 질문에 응답하기가 어려워집니다.

  • What is the top score ever recorded for the game Meteor Blasters?

  • Which user had the highest score for Galaxy Invaders?

  • What was the highest ratio of wins vs. losses?

키가 아닌 속성에 대한 쿼리 속도를 높이기 위해 글로벌 보조 인덱스를 만들 수 있습니다. 글로벌 보조 인덱스에는 기본 테이블의 부분 속성이 포함되어 있지만 테이블의 기본 키가 아닌 다른 기본 키를 기준으로 구성됩니다. 인덱스 키는 테이블의 키 속성을 가져야 할 필요가 없습니다. 테이블과 동일한 키 스키마를 가져야 할 필요도 없습니다.

예를 들어, 글로벌 보조 인덱스 이름 지정 GameTitleIndex, 파티션 키 포함 GameTitle 그리고 TopScore. 기본 테이블의 기본 주요 특성은 항상 인덱스로 투영되므로 UserId 애트리뷰트가 또한 존재합니다. 다음 그림은 GameTitleIndex 인덱스를 나타냅니다.


                타이틀, 점수 및 사용자 ID의 목록이 포함되어 있는 GameTitleIndex 테이블입니다.

이제 GameTitleIndex를 쿼리하여 Meteor Blasters의 점수를 쉽게 가져올 수 있습니다. 결과는 TopScore. 설정을 ScanIndexForward 파라미터가 거짓이기 때문에 결과는 내림차순으로 반환되므로 가장 높은 점수는 먼저 반환됩니다.

모든 글로벌 보조 인덱스에는 파티션 키가 있어야 하며 선택 사항으로 정렬 키를 가질 수 있습니다. 인덱스 키 스키마는 기본 테이블 스키마와 다를 수 있습니다. 단순 기본 키(파티션 키)가 있는 테이블을 가지고 복합 기본 키(파티션 키 및 정렬 키)가 있는 글로벌 보조 인덱스를 만들거나 —그 반대도 가능합니다. 인덱스 키 속성은 기본 테이블에서 나온 모든 최상위 수준 String, Number 또는 Binary 속성으로 구성될 수 있습니다. 다른 스칼라 유형, 문서 유형 및 집합 유형은 허용되지 않습니다.

다른 기본 테이블 속성을 인덱스로 프로젝션할 수도 있습니다. 인덱스를 쿼리할 경우 DynamoDB에서 이와 같이 프로젝션된 속성을 효율적으로 가져올 수 있습니다. 그러나 글로벌 보조 인덱스 쿼리는 기본 테이블에서 속성을 가져올 수 없습니다. 예를 들어 이전 다이어그램에 나와 있듯이 GameTitleIndex을 쿼리하는 경우, TopScore 이외의 어떤 키가 아닌 속성에도 액세스할 수 없습니다(키 속성 GameTitleUserId은 자동으로 프로젝션됨에도 불구하고).

DynamoDB 테이블에서 각 키 값은 고유성이 보장되어야 합니다. 하지만 글로벌 보조 인덱스의 키 값은 고유할 필요가 없습니다. 예를 들어 많은 새로운 사용자들이 도전하지만 0점을 넘지 못하는 특히 어려운 Comet Quest라는 게임이 있다고 가정해 보겠습니다. 아래에는 이를 표현할 수 있는 몇 가지 데이터가 나와 있습니다.

UserId GameTitle TopScore
123 Comet Quest 0
201 Comet Quest 0
301 Comet Quest 0

이 데이터가 GameScores 표 DynamoDB 이를 GameTitleIndex. Comet Quest를 사용하여 인덱스를 쿼리하는 경우 GameTitle 및 0 TopScore다음 데이터가 반환됩니다.


                타이틀, 최고 점수 및 사용자 ID의 목록이 포함되어 있는 테이블입니다.

지정된 키 값을 가진 항목만 응답에 나타납니다. 이러한 데이터 집합 내에서 항목들은 특정한 순서를 따르지 않습니다.

글로벌 보조 인덱스는 해당 키 속성이 실제로 존재하는 데이터 항목만을 추적합니다. 예를 들어 GameScores 테이블에 새 항목을 하나 더 추가하되 필요한 기본 키 속성만 제공한 경우를 가정하겠습니다.

UserId GameTitle
400 Comet Quest

귀하가 TopScore 애트리뷰트, DynamoDB 이 품목을 GameTitleIndex. 따라서 GameScores Comet Quest 항목에서 다음 4개 항목을 받게 됩니다.


                4개의 타이틀, 최고 점수 및 사용자 ID의 목록이 포함되어 있는 테이블입니다.

그러나 GameTitleIndex로 유사한 쿼리를 실행할 경우 4개가 아닌 3개 항목이 반환됩니다. 그 이유는 존재하지 않는 TopScore를 보유한 항목은 인덱스로 적용되지 않기 때문입니다.


                3개의 타이틀, 최고 점수 및 사용자 ID의 목록이 포함되어 있는 테이블입니다.

Attribute Projections

프로젝션은 테이블에서 보조 인덱스로 복사되는 속성 집합입니다. 테이블의 파티션 키와 정렬 키는 항상 인덱스로 프로젝션되지만, 다른 속성을 프로젝션하여 애플리케이션의 쿼리 요건을 지원하는 것도 가능합니다. 따라서 인덱스에 쿼리를 실행할 때는 마치 속성이 자체 테이블에 저장되어 있는 것처럼 Amazon DynamoDB가 프로젝션의 모든 속성에 액세스할 수 있습니다.

보조 인덱스를 생성할 때 인덱스에 프로젝션될 속성을 지정해야 합니다. DynamoDB는 속성 지정을 위해 다음과 같은 세 가지 옵션을 제공합니다.

  • KEYS_ONLY – 인덱스의 각 항목은 테이블 파티션 키 및 정렬 키 값, 그리고 인덱스 키 값으로만 구성됩니다. KEYS_ONLY 옵션은 보조 인덱스의 크기를 최소화합니다.

  • INCLUDEKEYS_ONLY에서 설명한 속성뿐만 아니라 키 외에 다른 속성을 지정하여 보조 인덱스에 추가합니다.

  • ALL – 보조 인덱스에 원본 테이블의 모든 속성이 추가됩니다. 모든 테이블 데이터가 인덱스에 복사되기 때문에 ALL 프로젝션은 보조 인덱스의 크기를 최대화합니다.

이전 다이어그램에서 GameTitleIndex 은(는) 하나의 예상 특성을 가집니다. UserId. 애플리케이션을 통해 UserId 각 게임에 대한 최고 점수를 GameTitle and TopScore 쿼리에서 최고 득점자의 손실 대 손실 비율을 효율적으로 결정할 수 없습니다. 확인하려면 기본 테이블에서 추가 쿼리를 실행하여 각 최고 득점자의 승패를 가져와야 합니다. 이 데이터에서 쿼리를 지원하는 더욱 효율적인 방법은 다음 그림과 같은 속성을 기본 테이블에서 글로벌 보조 인덱스로 프로젝션하는 것입니다.

키가 아닌 속성 WinsLosses는 인덱스로 프로젝션되기 때문에 애플리케이션으로 모든 게임 또는 모든 게임과 사용자 ID 조합에 대해 승률을 확인할 수 있습니다.

속성을 글로벌 보조 인덱스로 프로젝션하려면 프로비저닝 처리량 비용과 스토리지 비용 간 균형을 고려해야 합니다.

  • If you need to access just a few attributes with the lowest possible latency, consider projecting only those attributes into a 글로벌 보조 인덱스. The smaller the index, the less that it costs to store it, and the less your write costs are.

  • If your application frequently accesses some non-key attributes, you should consider projecting those attributes into a 글로벌 보조 인덱스. The additional storage costs for the 글로벌 보조 인덱스 offset the cost of performing frequent table scans.

  • If you need to access most of the non-key attributes on a frequent basis, you can project these attributes—or even the entire base table— into a 글로벌 보조 인덱스. This gives you maximum flexibility. However, your storage cost would increase, or even double.

  • If your application needs to query a table infrequently, but must perform many writes or updates against the data in the table, consider projecting KEYS_ONLY. The 글로벌 보조 인덱스 would be of minimal size, but would still be available when needed for query activity.

Reading Data from a 글로벌 보조 인덱스

에서 항목을 검색할 수 있습니다. 글로벌 보조 인덱스 사용 Query and Scan 작업. The GetItem and GetBatchItem 작업은 글로벌 보조 인덱스.

Querying a 글로벌 보조 인덱스

Query 작업을 사용하여 글로벌 보조 인덱스에서 하나 이상의 항목에 액세스할 수 있습니다. 쿼리는 사용하려는 인덱스의 이름과 기본 테이블의 이름, 쿼리 결과에 반환할 속성, 적용할 쿼리 조건을 지정해야 합니다. DynamoDB는 결과를 오름차순 또는 내림차순으로 반환할 수 있습니다.

순위표 애플리케이션에 대해 게임 데이터를 요청하는 Query에서 다음과 같은 데이터가 반환된 경우를 가정해 보십시오.

{ "TableName": "GameScores", "IndexName": "GameTitleIndex", "KeyConditionExpression": "GameTitle = :v_title", "ExpressionAttributeValues": { ":v_title": {"S": "Meteor Blasters"} }, "ProjectionExpression": "UserId, TopScore", "ScanIndexForward": false }

이 쿼리에서

  • DynamoDB accesses GameTitleIndex, using the GameTitle partition key to locate the index items for Meteor Blasters. All of the index items with this key are stored adjacent to each other for rapid retrieval.

  • Within this game, DynamoDB uses the index to access all of the user IDs and top scores for this game.

  • The results are returned, sorted in descending order because the ScanIndexForward parameter is set to false.

Scanning a 글로벌 보조 인덱스

Scan 작업을 사용하여 글로벌 보조 인덱스에서 모든 데이터를 검색할 수 있습니다. 요청에 기본 테이블 이름과 인덱스 이름을 제공해야 합니다. DynamoDB는 Scan을 사용하여 인덱스에 있는 모든 데이터를 읽고 애플리케이션에 반환합니다. 또한 일부 데이터만 반환하고 나머지 데이터를 무시하도록 요청할 수 있습니다. 그러려면 Scan 작업의 FilterExpression 파라미터를 사용합니다. 자세한 정보는 스캔에 대한 필터 표현식 단원을 참조하십시오.

Data Synchronization Between Tables and Global Secondary Indexes

DynamoDB는 각 글로벌 보조 인덱스를 기본 테이블과 자동으로 동기화합니다. 애플리케이션이 테이블에 항목을 쓰거나 삭제하면 해당 테이블의 글로벌 보조 인덱스가 최종적으로 일관된 모델을 사용하여 비동기적으로 업데이트됩니다. 애플리케이션이 인덱스에 직접 쓰기를 수행하는 경우는 없습니다. 하지만, DynamoDB가 이러한 인덱스를 유지하는 방식이 어떤 영향을 미치는지 이해하는 것이 중요합니다.

글로벌 보조 인덱스는 기본 테이블에서 읽기/쓰기 용량 모드를 상속합니다. 자세한 정보는 읽기/쓰기 용량 모드 변경 시 고려 사항 단원을 참조하십시오.

글로벌 보조 인덱스를 생성할 때 하나 이상의 인덱스 키 속성과 해당 데이터 형식을 지정합니다. 다시 말해, 기본 테이블에 항목을 쓸 때마다 해당 속성의 데이터 형식이 인덱스 키 스키마의 데이터 형식과 일치해야 합니다. GameTitleIndex의 경우, 인덱스의 GameTitle 파티션 키가 String 데이터 유형으로 정의됩니다. The TopScore 인덱스의 정렬 키는 유형 Number. 항목을 GameScores 테이블에 대한 다른 데이터 유형을 GameTitle 또는 TopScore, DynamoDB a ValidationException 데이터 유형이 일치하지 않습니다.

테이블에 항목을 추가하거나 삭제하면 해당 테이블의 글로벌 보조 인덱스가 최종 일관성 방식으로 업데이트됩니다. 정상적인 조건에서 해당 테이블 데이터의 변경 사항은 거의 밀리초 수준으로 글로벌 보조 인덱스에 적용됩니다. 하지만, 간혹 장애가 발생할 경우 긴 적용 지연이 발생할 수 있습니다. 따라서, 애플리케이션은 글로벌 보조 인덱스의 쿼리가 최신이 아닌 결과를 반환할 수 있음을 예상하고 그러한 상황을 처리할 수 있어야 합니다.

테이블에 항목을 쓸 경우 모든 글로벌 보조 인덱스 정렬 키에 대해 속성을 지정하지 않아도 됩니다. 예를 들어 GameTitleIndex의 경우, GameScores 테이블에 새 항목을 쓰기 위해 TopScore 속성의 값을 지정할 필요가 없습니다. 이 경우 DynamoDB는 이 특정 항목의 인덱스에 데이터를 쓰지 않습니다.

글로벌 보조 인덱스가 많은 테이블은 인덱스가 적은 테이블보다 쓰기 작업에 더 높은 비용이 발생합니다. 자세한 정보는 Provisioned Throughput Considerations for Global Secondary Indexes 단원을 참조하십시오.

Provisioned Throughput Considerations for Global Secondary Indexes

프로비저닝된 모드 테이블에서 글로벌 보조 인덱스를 생성할 때는 해당 인덱스에 예상되는 워크로드에 대한 읽기 및 쓰기 용량 단위를 지정해야 합니다. 글로벌 보조 인덱스의 프로비저닝 처리량 설정 값은 기본 테이블의 설정 값과 별개입니다. 글로벌 보조 인덱스의 Query 작업은 기본 테이블이 아닌 인덱스에서 읽기 용량 단위를 소비합니다. 테이블에 항목을 추가, 업데이트 또는 삭제하면 해당 테이블의 글로벌 보조 인덱스도 업데이트됩니다. 이러한 인덱스 업데이트에서는 기본 테이블이 아닌 인덱스의 용량 단위가 사용됩니다.

예를 들어 글로벌 보조 인덱스를 Query하고 프로비저닝된 읽기 용량을 초과할 경우 요청에 병목 현상이 발생합니다. 테이블에 많은 쓰기 작업을 수행할 때 해당 테이블의 글로벌 보조 인덱스에 충분한 쓰기 용량이 없을 경우 테이블의 쓰기 작업에 병목 현상이 발생합니다.

참고

잠재적 조절을 피하기 위해서 글로벌 보조 인덱스용 프로비저닝된 쓰기 용량은 새로운 업데이트로 기본 테이블과 글로벌 보조 인덱스가 모두 쓰여지기 때문에 기본 테이블의 쓰기 용량 이상이어야 합니다.

글로벌 보조 인덱스에서 프로비저닝된 처리량 설정을 변경하려면 DescribeTable을 사용합니다. 테이블의 모든 글로벌 보조 인덱스에 대한 세부 정보가 반환됩니다.

Read Capacity Units

글로벌 보조 인덱스는 최종적으로 일관된 읽기를 지원하며, 각각 읽기 용량 단위의 절반을 소비합니다. 즉, 단일 글로벌 보조 인덱스 쿼리는 읽기 용량 단위당 최대 2 × 4 KB = 8KB까지 검색할 수 있습니다.

글로벌 보조 인덱스 쿼리의 경우 DynamoDB는 테이블에 대한 쿼리와 같은 방식으로 프로비저닝된 읽기 작업을 계산합니다. 유일한 차이는 기본 테이블 항목의 크기가 아닌 인덱스 항목의 크기를 기준으로 계산이 이루어진다는 점입니다. 읽기 용량 단위의 수는 반환된 모든 항목에서 프로젝션된 모든 속성 크기의 합계입니다. 그런 다음 결과가 다음 4 KB 경계로 반올림됩니다. DynamoDB에서 프로비저닝된 처리량을 계산하는 방법에 대한 자세한 내용은 DynamoDB 프로비저닝된 용량 테이블의 설정 관리 단원을 참조하십시오.

Query 작업에서 반환된 결과의 최대 크기는 1 MB입니다. 여기에는 반환된 모든 항목의 속성 이름 및 값의 크기가 포함됩니다.

예를 들어 각 항목에 2000바이트의 데이터가 포함된 글로벌 보조 인덱스를 가정해 보겠습니다. 이제 이 인덱스를 Query했을 때 쿼리에서 8개 항목을 반환한 경우를 가정해 보십시오. 일치하는 항목의 총 크기는 2,000바이트(× 8개 항목 = 16,000바이트)입니다. 그런 다음 결과가 가장 가까운 4 KB 경계로 반올림됩니다. 글로벌 보조 인덱스 쿼리는 최종적으로 일관되므로 총 비용은 0.5 ×(16KB/4 KB), 즉 2 읽기 용량 단위입니다.

Write Capacity Units

테이블에 항목을 추가, 업데이트 또는 삭제하고 이로 인해 글로벌 보조 인덱스가 영향을 받을 경우 글로벌 보조 인덱스에서 작업에 프로비저닝된 쓰기 용량 단위를 소비합니다. 쓰기의 총 할당된 처리량 비용은 기본 테이블에 쓰기 작업으로 소비된 쓰기 용량 단위와 글로벌 보조 인덱스를 업데이트하여 소비된 쓰기 용량 단위의 합계로 구성됩니다. 글로벌 보조 인덱스 업데이트가 필요하지 않은 테이블 쓰기의 경우 인덱스에서 쓰기 용량이 소비되지 않습니다.

테이블 쓰기가 성공하기 위해서는 테이블 및 모든 글로벌 보조 인덱스의 프로비저닝 처리량 설정에 쓰기를 수용할 수 있을 만큼 충분한 쓰기 용량이 있어야 합니다. 그렇지 않을 경우 테이블에 대한 쓰기에 병목 현상이 발생합니다.

글로벌 보조 인덱스에 항목을 쓰는 비용은 몇 가지 요인에 따라 달라집니다.

  • If you write a new item to the table that defines an indexed attribute, or you update an existing item to define a previously undefined indexed attribute, one write operation is required to put the item into the index.

  • If an update to the table changes the value of an indexed key attribute (from A to B), two writes are required, one to delete the previous item from the index and another write to put the new item into the index. 

  • If an item was present in the index, but a write to the table caused the indexed attribute to be deleted, one write is required to delete the old item projection from the index.

  • If an item is not present in the index before or after the item is updated, there is no additional write cost for the index.

  • If an update to the table only changes the value of projected attributes in the index key schema, but does not change the value of any indexed key attribute, one write is required to update the values of the projected attributes into the index.

이러한 모든 요인은 인덱스에 있는 각 항목의 크기가 쓰기 용량 단위를 계산하기 위한 1 KB 항목 크기보다 작거나 같은 경우를 가정합니다. 이보다 큰 인덱스 항목에서는 추가 쓰기 용량 단위가 필요합니다. 쿼리에서 어떤 속성을 반환해야 하는지 고려하고 해당 속성만 인덱스에 프로젝션함으로써 쓰기 비용을 최소화할 수 있습니다.

Storage Considerations for Global Secondary Indexes

애플리케이션에서 테이블에 항목을 쓰는 경우 DynamoDB는 해당 속성이 표시되어야 하는 모든 글로벌 보조 인덱스에 올바른 속성 하위 집합을 자동으로 복사합니다. AWS 계정에는 기본 테이블의 항목 스토리지 및 해당 테이블에 있는 글로벌 보조 인덱스의 속성 스토리지 비용이 청구됩니다.

인덱스 항목에서 사용하는 공간의 양은 다음의 합계입니다.

  • The size in bytes of the base table primary key (partition key and sort key)

  • The size in bytes of the index key attribute

  • The size in bytes of the projected attributes (if any)

  • 100 bytes of overhead per index item

글로벌 보조 인덱스의 스토리지 요구 사항을 추정하려면 인덱스의 평균 항목 크기를 추정한 다음 기본 테이블에서 글로벌 보조 인덱스 키 속성이 있는 항목의 수를 곱합니다.

테이블에 특정 속성이 정의되지 않은 항목이 포함되어 있지만 해당 속성이 인덱스 파티션 키 또는 정렬 키로 정의된 경우 DynamoDB에서 해당 항목의 데이터를 인덱스에 쓰지 않습니다.