중급7분 분량

DynamoDB GROUP BY: 대신 집계하는 방법

DynamoDB에는 GROUP BY가 없습니다. COUNT, SUM, AVG이 없습니다. 둘 중 하나 — 네이티브 API도 아니고 PartiQL에도 없습니다. DynamoDB는 키-값 / 분석 엔진이 아닌 문서 저장소이므로 집계는 귀하가 담당합니다. 쿼리 플래너가 대신 수행하는 작업이 아닙니다.

DynamoDB에서 GROUP BY를 사용할 수 있나요?

아니요. DynamoDB에는 GROUP BY, HAVING 또는 COUNT, SUM, AVG와 같은 집계 함수가 없습니다. 네이티브 API에도 없고 PartiQL에도 없습니다. SELECTWHEREORDER BY만 허용합니다. 데이터 변경(원자 카운터 또는 + Lambda 롤업)에 따라 총계를 미리 계산하거나 읽은 후 앱 측을 그룹화하여 집계합니다.

  • DynamoDB의 PartiQL SELECT 문법은 SELECT … FROM … [WHERE …] [ORDER BY …]입니다. — 이것이 전체 목록입니다. GROUP BY 없음, HAVING 없음, 집계 없음 기능, JOIN(AWS PartiQL 17 reference) 없음.
  • DynamoDB는 "기본적으로 SUM과 같은 집계 작업을 지원하지 않기 때문입니다. 또는 COUNT 전체 항목"에 대해 AWS 자체 지침은 집계를 사전 계산하는 것입니다. 데이터가 변경되면 결과를 일반 항목으로 저장합니다. (AWS: materialized aggregation).
  • 모든 항목을 읽은 다음 앱에 집계하는 대안이 효과적이지만 모든 쿼리에서 전체 테이블을 읽으려면 비용을 지불하세요.
  • 일회성 탐색을 위해 DynoTable의 SQL WorkbenchGROUP BY / COUNT / SUM / AVG를 라이브 테이블에 대해 직접 — SQL DynamoDB의 PartiQL 엔드포인트가 거부됩니다.

DynamoDB에서 집계가 어려운 이유

DynamoDB에는 스캔 시간 집계 엔진이 없습니다. QueryScan 반품 항목; 그들은 접지 않습니다. Scan은 전체 테이블을 한 번에 1MB씩 읽습니다. 소비하는 용량은 보관하는 행이 아닌 읽는 항목을 기반으로 합니다. FilterExpression은 스캔 적용되지만 결과가 반환되기 _전_이므로 청구서를 낮추지 않고 결과 집합의 범위를 좁힙니다 (AWS 28 API reference: 필터 "추가 읽기 용량 단위를 소비하지 않습니다"; 용량은 항목에 따라 다릅니다. 크기가 스캔되었으므로 반환되지 않습니다). GROUP-BY 후크가 없습니다. 우선 금액을 계산하거나 의지하는 것입니다.

PartiQL은 이를 변경하지 않습니다. PartiQL은 동일한 SQL-호환 방언입니다. 엔진이므로 동일한 제한을 상속받습니다. 이는 새로운 구문이 아닌 구문 표면입니다. 실행 모델. documented 29 grammar 단순히 GROUP BY 토큰이 없습니다. PartiQL과 실제 SQL 간의 완전한 차이는 다음을 참조하세요. PartiQL vs SQL.

집계가 어디에 있고 언제 계산되는지 물어보십시오. 세 가지 대답이 있습니다.

패턴 1: 쓰기 시 집계(원자 카운터)

그룹을 미리 알고 있는 경우 — 상태별 개수, 고객별 합계, 월별 다운로드 — 카운터 항목을 유지하고 기록할 때마다 업데이트합니다.

ADD 를 사용하면 증분은 원자적이고 동시성이 안전합니다. ADD은 숫자와 집합에 대해 작동하며 읽기-수정-쓰기 경쟁을 피합니다. 동일한 카운터를 증가시키는 두 명의 작성자는 서로 충돌하지 않습니다. (AWS notes the atomic 2 "avoids read-modify-write race conditions"):

UpdateItem
Key                         { pk: "STATS#orders", sk: "status#shipped" }
UpdateExpression            "ADD orderCount :one"
ExpressionAttributeValues   { ":one": 1 }

이것은 귀하의 SELECT COUNT(*) … GROUP BY status입니다. 단, 카운트가 이미 완료되었습니다. 한 자리 밀리초 GetItem 단위로 읽을 수 있는 항목으로 거기에 앉아 있습니다. 는 절충: 작성 시 그룹화 키를 알아야 하며, 쓰기 경로에 대한 카운터 업데이트. 쓰기 후에 앱이 충돌하지만 카운터 업데이트 전에 두 가지가 동기화되지 않은 드리프트 — 이는 정확히 실패 모드에서는 다음 패턴이 분리됩니다.

패턴 2: DynamoDB 스트림 + Lambda 롤업

쓰기 경로에 집계 논리를 원하지 않거나 쓰기가 일반 PutItem은 쉽게 포장할 수 없습니다. 하류로 이동하세요. 이는 AWS 자체의 것입니다. 추천 패턴, 구체화된 집합 (AWS: Using GSIs for materialized aggregation queries):

  1. 앱이 원시 항목(주문, 다운로드, 이벤트)을 작성합니다. 집계 없음 논리.
  2. 은 쓰기를 스트림 레코드로 캡처합니다.
  3. 스트림에 연결된 Lambda는 새 항목을 읽고 그룹을 파생시킵니다. (상태, 월, 카테고리…) 및 1을 일치하는 집계 항목에 연결합니다. 원자 UpdateItem — "읽기-수정-쓰기 경쟁 조건을 방지"합니다. 많은 호출이 동일한 카운터에 닿습니다.
  4. 미리 계산된 집계를 쿼리합니다. 종종 을 통해 롤업 항목만 인덱싱하므로 "이번 달 상위 10개"는 다음과 같은 Query입니다. Limit 10.

희소 GSI 트릭: 집계 항목만 색인된 속성을 갖습니다. (예: Month), 원시 이벤트 행은 인덱스에서 자동으로 제외됩니다. — 인덱스를 유지하는 "테이블의 전체 항목 중 작은 부분" 저렴하고 빨리 읽혀요.

이는 쓰기 경로에서 집계를 분리하고 쓰기를 단순하게 유지합니다. 최종 일관성 비용 — AWS는 "결과 사이에 몇 초의 지연이 발생합니다. 다운로드가 기록되고 집계가 업데이트되고 있습니다." 대시보드의 경우 리더보드, 트렌드 카운터 등은 괜찮습니다.

동일한 재시도 주의 사항이 적용됩니다. 다시 시도된 Lambda 호출은 ADD를 다시 실행하므로 "재시도하면 횟수가 두 번 이상 증가합니다." 대략적인 결과가 남습니다. 가치. 정확한 수를 얻으려면 멱등성을 추가하세요(예: 조건식 입력 소스 항목의 ID); 그렇지 않으면 작은 마진이 분석에 적합하고 리더보드.

패턴 3: 스캔/쿼리 후 앱 측 그룹화

무차별 옵션: 항목을 읽고 코드에서 그룹화합니다.

groups = {}
resp = table.scan()                        # or query() for one partition
while True:
    for item in resp["Items"]:
        key = item["status"]
        groups[key] = groups.get(key, 0) + 1
    if "LastEvaluatedKey" not in resp:
        break
    resp = table.scan(ExclusiveStartKey=resp["LastEvaluatedKey"])

이것은 정확하고 때로는 올바른 결정입니다. 그러나 비용에 대해서는 솔직하게 말씀하십시오. 에이 Scan테이블의 모든 항목을 읽으며 읽기 용량은 동일합니다. 필터링하든 안 하든. 따라서 전체 Scan에 대한 앱측 그룹화는 비용을 지불한다는 의미입니다. 모든 집계에서 전체 테이블을 읽으려면 테이블이 늘어날수록 대기 시간도 늘어납니다. AWS는 "읽기 시 스캔 및 계산"을 "매우 작은 경우에만 적합"으로 표시합니다. 대기 시간이 문제가 되지 않는 데이터 세트" (AWS: Why pre-compute aggregations).

Query를 통해 단일 파티션으로 범위를 좁힙니다(예: 하나의 주문을 계산합니다) 고객), 앱측 그룹화는 완벽하게 합리적입니다. 단 하나만 읽고 있는 것입니다. 아이템 컬렉션. 둘 사이의 전체 비용 차이는 다음을 참조하세요. Query vs Scan. us-east-1 온디맨드에서는 풀 테이블 4개 청구서 4KB당 0.5RCU 검사한 모든 항목에 대해 최종적으로 일관됨 — 앱 이전의 1KB 행으로 구성된 1GB 테이블은 대략 250,000 RCU입니다. 무엇이든 그룹화하세요. 대표적인 품목의 크기를 다음과 같이 지정합니다. item-size calculator, 그런 다음 회선 등급을 지정합니다. pricing calculator에서 스캔하세요.

DynamoDB 테이블을 통한 진정한 임시 분석 SQL의 경우 - 일회용 "GROUP BY status, count them"을 한 번 실행하면 — AWS의 대답은 다음을 가리키는 것입니다. 별도의 엔진: Amazon Athena DynamoDB 커넥터를 사용하면 쿼리할 수 있습니다. 실제 SQL이 포함된 테이블(GROUP BY, 집계, 심지어 다른 소스에 대한 JOIN) Lambda 커넥터를 통해 (AWS: Amazon Athena DynamoDB connector). 무대 뒤에서 테이블을 스캔하므로 핫 패스가 아닌 보고/BI 도구입니다.

어떤 패턴을 사용하나요?

당신은...사용
핫 읽기 경로의 알려진 그룹 합계패턴 1 — 원자 계수기(ADD)
쓰기 경로를 건드리지 않고 집계패턴 2 — 스트림 + Lambda 롤업
하나의 파티션으로 범위가 지정된 개수패턴 3 - Query 다음 앱에서 그룹화
정확한 합계, 드리프트 없음패턴 1/2 멱등성 가드 포함
탐색 중 일회성 GROUP BYDynoTable Workbench(아래) 또는 Athena
SQL을 사용한 반복 BI/보고Athena DynamoDB 커넥터

DynoTable의 SQL Workbench에서 직접 GROUP BY 실행

위의 패턴은 프로덕션에서 집계를 제공하는 방법입니다. 하지만 당신이 언제 테이블 탐색 — "현재 상태당 주문 수는 얼마입니까?" — 당신은 원하지 않습니다 Lambda를 프로비저닝하거나 Athena를 세우세요. 쿼리를 입력하고 싶습니다.

이것이 바로 DynoTable의 SQL Workbench입니다. 실제 SQL을 실행합니다 — GROUP BY, COUNT, SUM, AVG, HAVING, 심지어 JOIN — 귀하의 라이브 DynamoDB 테이블, 해당 행에 대해 클라이언트 측 집계 실행 읽습니다. DynamoDB의 PartiQL 엔드포인트가 거부하는 SQL은 다음과 같습니다.

SELECT status, COUNT(*) AS orders, SUM(total) AS revenue
FROM "Orders"
GROUP BY status
HAVING SUM(total) > 1000
ORDER BY revenue DESC

정직한 프레이밍: DynoTable은 내부적으로 API가 허용하는 방식으로 항목을 읽습니다. (할 수 있는 곳에서는 Query, 해야 하는 곳에서는 Scan), 그것들을 구체화하고, 워크벤치에서 그룹화 — 패턴과 동일한 "읽기 후 집계" 메커니즘 3, 루프가 없고 DynamoDB의 액세스 패턴 규칙 내에서. 그것은 프로덕션 교체용이 아닌 탐색 및 임시 분석용으로 제작됨 핫 읽기 경로에서 롤업합니다. 이를 위해 미리 계산합니다(패턴 1/2).

동일한 웨지의 JOIN 면에 대해 — DynoTable은 크로스 테이블을 실행하여 PartiQL에 합류합니다. 둘 중 하나도 할 수 없습니다. DynamoDB JOIN을 참조하세요. GUI 비교 클라이언트가 정확히 이 기능을 사용하고 있나요? 참조 the DynamoDB GUI comparison.

FAQ

DynamoDB PartiQL은 GROUP BY를 지원합니까? 아니요. DynamoDB의 PartiQL SELECTWHEREORDER BY만 지원합니다. — 아니요 GROUP BY, HAVING, 집계 함수 또는 JOIN. 문법은 documented SELECT … FROM … [WHERE …] [ORDER BY …]로.

DynamoDB 테이블 전체에 대해 COUNT(*)를 수행할 수 있습니까? 집계 함수가 아닙니다. PartiQL에는 아무것도 없습니다. API는 당신에게 Scan/Query에 대한 Select=COUNT, 이는 _일치하는 항목의 수_를 반환하지만 여전히 스캔이 닿는 모든 항목을 읽고 청구합니다. (AWS 14 API reference: 용량은 검사한 품목에 따라 결정되며 반환되지 않습니다.) 자주 읽는 글의 경우 전체적으로 카운터 항목을 유지합니다(패턴 1).

파티션 키를 GROUP BY할 수 있나요? DynamoDB나 PartiQL에는 없습니다. "파티션 키별"이 알려진 액세스 패턴인 경우 원자 ADD(패턴 1)로 키당 하나의 집계 항목을 유지하거나 이를 굴립니다. Streams + Lambda(패턴 2)를 사용합니다.

그룹당 SUM 또는 AVG은 어떻게 하나요? SUM: 그룹당 누계를 유지하고 쓰기 시 ADD를 유지합니다. AVG: 매장 읽기 시간에 합계와 개수 및 나누기를 모두 수행합니다. 기본 평균은 없습니다. 일회성 탐색 AVG의 경우 DynoTable의 SQL Workbench에서 실행하거나 Athena DynamoDB 커넥터.

partiql group by 해결 방법이 있나요? PartiQL 쪽은 없습니다. 집계(카운터/스트림)를 미리 계산하고 SELECT 롤업 항목, 또는 하나가 있는 엔진에서 GROUP BY 실행 — 임시 보고를 위한 DynoTable의 Workbench, 반복 보고를 위한 Athena.


Lambda를 작성하지 않고 자신의 테이블에 대해 GROUP BY을 실행하고 싶으십니까? Try DynoTable 그리고 SQL Workbench를 라이브 테이블로 지정합니다.

업데이트됨